Отслеживание цели: когда ускорить и замедлить вращающуюся турель?

24

Скажем, у меня есть движущийся циркуляр, targetопределенный как:

Vector2 position;
Vector2 velocity;
float radius;

И вращающийся turret(установленный на движущемся транспортном средстве), определенный как:

Vector2 position;
Vector2 velocity;
float angle; // radians
float angularVelocity; // radians per second
const float maxAngularVelocity; // radians per second
const float maxAngularAcceleration; // radians per second per second

(Или что-то в этом духе. Обратите внимание, что положение и скорость обоих контролируются в другом месте - предположим, что скорость постоянна, а положение изменяется в зависимости от скорости.)

Я пытаюсь написать две связанные функции AI для определения в данном кадре:

  • Какое угловое ускорение (и в каком направлении) применить к углу башни, чтобы башня была направлена ​​на цель?

  • Если цель в данный момент находится в поле зрения, можно ли ее (любую часть в пределах ее радиуса) держать в поле зрения в течение xнескольких секунд, где xбудет доля секунды? (Альтернативно: есть ли другая стратегия, чтобы убедиться, что цель на самом деле «зафиксирована», а не просто летит через прицел?)

И я мог бы использовать некоторую помощь ...

Эндрю Рассел
источник
1
У вас могут быть разные значения для ускорения и замедления вращения - в реальном мире один, вероятно, двигатель, а другой - тормоз.
e100

Ответы:

19

Сначала вам нужно определить разницу в угле между направлением башни и направлением на цель.

Vector2 turretToTarget = target.position - turret.position;
float desiredAngle = atan2(turretToTarget.y, turretToTarget.x);
float angleDiff = desiredAngle - turret.angle;

// Normalize angle to [-PI,PI] range. This ensures that the turret
// turns the shortest way.
while (angleDiff < -PI) angleDiff += 2*PI;
while (angleDiff >= PI) angleDiff -= 2*PI;

Как только у вас есть эти величины, вы можете установить выражение второй степени для угла револьверной головки. Вы должны вычислять это при каждом обновлении, чтобы всегда использовать самые последние данные о позициях и скоростях.

// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;

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

Теперь положительные константы (не обязательно программные константы) должны быть определены и сбалансированы, чтобы система работала хорошо. C0является основным элементом управления скоростью системы. Высокое значение для C0даст быструю скорость поворота, а низкое значение даст низкую скорость поворота. Фактическое значение зависит от многих факторов, поэтому вы должны использовать метод проб и ошибок здесь. C1контролирует величину демпфирования. Дискриминант квадратного уравнения говорит нам , что если C1*C1 - 4*C0 >= 0мы имеем систему , не колеблющийся.

// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.

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

Также важно отметить, что этот код вычисляет только угловое ускорение. Угол и угловая скорость должны быть обновлены откуда-то еще, используя какой-либо интегратор. Из вопроса я предполагаю, что это было покрыто.

Наконец, есть что сказать об отставании, потому что турель, вероятно, всегда будет отставать при отслеживании быстрой цели. Простой способ справиться с этим - добавить линейный прогноз к позиции цели, то есть всегда стремиться немного вперед в направлении цели.

// Improvement of the first lines above.
const float predictionTime = 1; // One second prediction, you need to experiment.
Vector2 turretToTarget = target.position + predictionTime * target.velocity - turret.position;
/// ...

Что касается удержания револьверной головки в радиусе цели в течение некоторого времени, это может быть жестким требованием для непосредственного наложения на такую ​​систему. Вы можете быть уверены, что этот контроллер будет стремиться всегда держать турель направленной на цель (или, скорее, на прогнозируемую позицию). Если результат оказывается не удовлетворительным , вы должны изменить параметры predictionTime, C0и C1( в пределах стабильных границ).

Staffan E
источник
Я не квалифицирован, чтобы сказать, если это правильно или нет, но это звучит как некоторые умные вещи! В прошлом я решал подобные проблемы, прогнозируя эффект ускорения, чтобы определить, когда нужно ускоряться, а когда «применять разрывы». Означает ли это, что я делал это неправильно?
Иан
Atan2 затрудняет адаптацию этого метода к прогнозирующей системе, поскольку параметры x и y для atan2 становятся зависимыми от t.
Skizz
Это именно то решение, на которое я намекал в своем ответе ниже. Отличная детализация и презентация!
drxzcl
@ Иайн: Нет, здесь нет правильных и неправильных. Хотя я полагаю, что ваш метод будет иметь два дискретных состояния: ускорение / замедление, этот метод основан на регуляторе из теории управления, который масштабирует ускорение для получения быстрого отклика, одновременно уменьшая выбросы и колебания.
Staffan E
1
Как и в других комментариях, это будет работать для стационарной цели, но, вероятно, будет неприемлемым для любых движущихся целей. Термины C0 и C1 являются традиционным демпфирующим материалом пружины, где C0 представляет прочность пружины (обычно называемый k), а C1 - коэффициент демпфирования (обычно называемый «B» или «c»). Так что да, вы можете минимизировать колебания, увеличивая демпфирование, но проблема в том, что он не пытается предвидеть, где будет цель , поэтому обречен на отставание от желаемой цели.
дэш-том-бэнг
3

То, что у вас здесь есть, является основной проблемой контроля . Турель - это система, ускорение - это контроль, а датчик измеряет положение / скорость. Есть много способов решения этих проблем, так как это очень хорошо изученная проблема в технике.

Ключ заканчивается стабильной системой, то есть системой, которая не генерирует колебания. Обычно это делается путем добавления демпфирования. Страница википедии должна помочь вам начать.

drxzcl
источник
2

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

ОК, это казалось простым. Тем не менее, вы должны действительно попытаться предвидеть положение цели, так как цель будет двигаться к тому времени, как вы повернули турель. Сделать это:-

Pd' = Pd + t.Vd
Ps' = Ps + t.Vs

где P - это положение, а V - это скорость, а нижний индекс равен d для пункта назначения (цель) и s для источника (турель), что дает вектор направления:

Dsd' = Pd' - Ps' = Pd + t.Vd - (Ps + t.Vs) = Pd - Ps + (Vd - Vs).t

где D - вектор направления, а Dsd '- требуемое направление в момент времени t. Теперь определите направление револьверной головки на основе текущего положения и максимальной скорости и ускорения для заданного времени t:

Ds' = t.Ds.Rs -> this is a vector rotation

Ds и Ds '- направления источника, а Rs - скорость вращения. При всем этом вы хотите найти t для требуемой скорости вращения, когда Dsd '== Ds' и, следовательно, Rs. Не забывайте, что все P, D и V имеют компоненты x и y.

Здесь я не учел ускорение - это значительно увеличивает сложность. Получив Rs и t, вы, вероятно, можете приблизить параболическое Rs (то есть ускорить и замедлить), чтобы получить тот же результат.

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

То, что вы, вероятно, ищете здесь, - это PID-контроллер , аналогичный ответу, принятому на этот вопрос SO

Первоначально я ответил на этот вопрос, «катясь самостоятельно», но этот ответ значительно более полный и элегантный.

nicolaskruchten
источник
0

Первое, что нужно сделать, - это рассчитать угол между потоком и отслеживаемым объектом.
Далее нужно проверить, будет ли использование текущей скорости торрента и максимальное ускорение назад (остановка торрента) останавливать торрент до или после отслеживаемого объекта.
Если ответ таков: торрент остановится перед отслеживаемым объектом, примените максимальное ускорение вперед (увеличение скорости).
Если ответ таков: торрент остановится после отслеживаемого объекта, примените максимальное ускорение в обратном направлении (остановите торрент).
Таким образом, торрент всегда прибудет быстрее всех и остановится в нужной точке (или немного позже).

Дани
источник