Unity C # стреляет снарядом по цели, вращающейся вокруг движущейся оси - PullRequest
0 голосов
/ 24 мая 2018

Я занимаюсь разработкой трехмерной космической игры, в которой камера находится в постоянном двухмерном (сверху вниз) состоянии.Я могу стрелять снарядом со скоростью (скоростью) по цели, движущейся с заданной скоростью, и каждый раз поражать ее.Большой!Хорошо, а что если эта цель имеет угловую скорость вокруг родителя?Я заметил, что если у цели есть вращающийся родительский объект, моя проекция неверна, поскольку она не учитывает угловую скорость.

Мой исходный код был построен на предположении, что:

Position_target + Velocity_target * t = Position_shooter + Velocity_shooter * t + Bulletspeed * t

Я предполагаю, что стрелок стоит (или потенциально движется) и нуждается в стрельбе пулей с постоянной величиной.

Я упрощаю вышеизложенное до этого

Delta_Position = Position_target - Position_shooter
Delta_Velocity = Velocity_target - Velocity_shooter

Delta_Position + Delta_Velocity * t = BulletSpeed * t

Возводя квадрат в обе стороны, я прихожу к квадратному уравнению, где я могу решить для заданных определяющих результатов или нулей.Это работает отлично.Я возвращаюсь к значению, а затем проецирую позицию цели и текущую скорость на это t, и затем у меня есть сценарии турелей, которые вращаются с заданной угловой скоростью в направлении этой точки.Если турель говорит, что смотрит в эту точку в пределах 1% по всей оси, она стреляет пулей со скоростью (-ями) и наносит 100% -ный удар, если цель не изменяет свой курс или скорость.

Я начал добавлять компоненты на своих кораблях / астероидах, которые были дочерними по отношению к родительскому объекту, подобно башне, прикрепленной к кораблю, где сама башня является целью.Если корабль вращается вокруг оси (например, оси Y) и турель не находится в точке x = 0 и z = 0, моя проекция больше не работает.Я думал, что использование r * sin (тета + омега * t) в качестве компонента угловой скорости для позиции X и r * cos (тета + омега * t) для позиции Z может сработать.Тета - текущее вращение (относительно мировых координат), а омега - вращение eulerAngle вокруг оси y.

Я быстро понял, что это работает только с вращением вокруг оси y, и я не могу поместить грех в квадратное уравнение, потому что я не могу извлечь t из него, поэтому я не могу спроецироватьэто соответственно.Я пытался использовать гиперболики, но это была та же самая ситуация.Я могу создать произвольное t, скажем, t = 2, и вычислить, где объект будет через 2 секунды.Но я изо всех сил пытаюсь найти способ реализовать проекцию скорости пули с помощью этого.

Position_targetparent + Velocity_targetparent * t + [ANGULAR VELOCITY COMPONENT] = Position_shooter + Velocity_shooter * t + Bulletspeed * t

Delta_Position_X + Delta_Velocity_X * t + S * t = r * sin (theta + Omegay * t)
Delta_Position_Z + Delta_Velocity_Z * t + S * t = r * cos (theta + Omegay * t)

Отсюда я бесконечно крутил свои колеса, пытаясь найти подходящее решение для этого.Я использую eulerAngle.y для омеги, которая работает хорошо.В конечном счете мне просто нужна та мгновенная точка в пространстве, которую я должен выстрелить, которая является продуктом скорости пули и расстояния проекции, и тогда мои сценарии наведения турелей позаботятся обо всем остальном.

Я смотрел на сферическую систему координат, основанную вокруг положения родителей (центр вращения)

Vector3 deltaPosition = target.transform.position - target.transform.root.position;
r = deltaPosition .magnitude;
float theta = Mathf.Acos(deltaPosition.z / r);
float phi = Mathf.Atan2(deltaPosition.y,deltaPosition.x);

float xPos = r * Mathf.Sin(theta) * Mathf.Cos(phi)
float yPos = r * Mathf.Sin(theta) * Mathf.Sin(phi)
float zPos = r * Mathf.Cos(theta)

Vector3 currentRotation = transform.root.gameObject.transform.rotation.eulerAngles * Mathf.Deg2Rad;
Vector3 angularVelocity = transform.root.gameObject.GetComponent<Rigidbody>().angularVelocity;

Я могу рассчитать положение объекта с учетом этих углов ... но я изо всех сил пытаюсь повернутьэто что-то, что я могу использовать с подходом omega * t (угловая скорость).

Мне интересно, есть ли более элегантный подход к этой проблеме или кто-то может указать мне правильное направление формулы, чтобы помочь мне обдумать это?Я не лучший в Quaternions и EulerAngles, но я учу их медленно.Может быть, что-нибудь умное, что я могу с ними сделать?

Ответы [ 2 ]

0 голосов
/ 21 июля 2019

Я предлагаю решить эту проблему приблизительно.
Если вы можете описать положение вашей цели функцией по времени, f (t), то вы можете аппроксимировать ее, используя стратегию «разделяй и властвуй» вот так:

Алгоритм (псевдокод):
Пусть f (t: float): Vector3 будет функцией, которая вычисляет позицию целив момент времени t
Пусть g (p: Vector3): float будет функцией, которая вычисляет, как долго пуля должна достичь p

float begin = 0    // Lower bound of bullet travel time to hit the target
float end = g(target.position)    // Upper bound

// Find an upper bound so that the bullet can hit the target between begin and end time
while g(f(end)) > end:
    begin = end
    end = end * 2    // Exponential growth for fast convergence
    // Add break condition in case the target can't be hit (faster than bullet)
end    

// Narrow down the possible aim target, doubling the precision in every step
for i = 1...[precision]:
    float center = begin + (end - begin) / 2
    float travelTime = g(f(center))

    if travelTime > center:    // Bullet can't reach target
        begin = center
    else    // Bullet overtook target
        end = center
    end
end

float finalTravelTime = begin + (end - begin) / 2
Vector3 aimPosition = f(finalTravelTime)    // You should aim here...

Вам необходимо поэкспериментировать со значением для [точности].Оно должно быть как можно меньше, но достаточно большим, чтобы пуля всегда поражала цель.
Вы также можете использовать другое условие разрыва, например, ограничение абсолютной ошибки (расстояние пули до цели в finalTravelTime).
В случае, если цель может двигаться быстрее, чем пуля, вам нужно добавить условие разрыва в верхнюю границу петли, иначе она может стать бесконечной петлей.

Почему это полезно:
Вместо того, чтобы вычислять сложную функцию равенства для определения времени удара, вы можете аппроксимировать ее довольно простой функцией положения и этим методом.
Этот алгоритм не зависит от фактической функции положения, поэтому работает с различнымиДвижения противника, если можно рассчитать будущую позицию.

Недостатки:
Эта функция много раз вычисляет f (t), это может быть интенсивным ЦП для комплекса f (t).
Также это только приближение, где точность результата ухудшаетсяДругими словами, время в пути:

Примечание:
Я написал этот алгоритм из головы.
Я не гарантирую правильность псевдокода, ноалгоритм должен работать.

0 голосов
/ 02 октября 2018

Хотя математика, вероятно, все еще сложна, я подозреваю, что вы можете существенно упростить математику, если «цель» вычислит свою будущую позицию в локальном пространстве.И затем, когда он вызывает это местоположение для своего родителя, рассчитывает его в локальном пространстве и так далее вверх по иерархии, пока вы не достигнете мирового пространства.Как только вы достигнете своей будущей позиции в мировом пространстве, вы можете нацелить свою башню на эту цель.

Например, орбитальный корабль должен иметь возможность легко вычислять свою будущую орбиту.Это уравнение для эллипса.Который затем может отправить эту локальную позицию своему родителю (планете), которая, вероятно, также находится на орбите, и вычислить эту позицию относительно себя.Планета затем отправит эту локальную позицию своему родителю (Звезде) и так далее.Пока вы не попадете в мировое пространство.

Вы можете еще больше упростить эту математику, сделав постоянным время перемещения пули (гибкую скорость), чтобы вы могли упростить определение будущей позиции в определенное время.В зависимости от масштаба вашей игры, фактическая разница в скорости может быть не такой разной.

Другая идея: вместо того, чтобы делать все расчеты методом грубой силы, вы могли бы «симулировать» целевой объект вперед во времени.Убедитесь, что весь код, который влияет на положение, может быть запущен отдельно от вашего фактического цикла обновления.Просто продвиньте время на час вперед и посмотрите на его будущее положение, фактически не перемещая его.Затем вернитесь в настоящее и стреляйте из пистолета в его будущее положение.

...