Відстеження цілі: Коли прискорити та зменшити обертову башту?


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( в межах стабільних кордонів).


Я не кваліфікований, щоб сказати, правильно це чи ні, але це звучить як якісь розумні речі! У минулому я вирішував ці проблеми, передбачуючи прогноз ефекту прискорення, коли потрібно розганятись і коли "застосовувати перерви". Це означає, що я робив це неправильно?
Iain

Atan2 утруднює цей метод у адаптації до системи прогнозування, оскільки параметри x і y для atan2 стають залежними від t.
Skizz

Це саме рішення, на яке я натякав у своїй відповіді нижче. Відмінна деталізація та презентація!
drxzcl

@Iain: Ні тут немає правильного і неправильного. Хоча я здогадуюсь, що ваш метод матиме два дискретні стани: прискорення / уповільнення, цей метод надихається регулятором з теорії управління, масштабуючи прискорення для швидкого реагування, зменшуючи при цьому простріл та коливання.
Staffan E

1
Як і в інших коментарях, це буде працювати для нерухомої цілі, але, ймовірно, буде неприйнятним для будь-яких рухомих цілей. Терміни C0 і C1 - це традиційні демпфіровані пружинні речі, де C0 являє собою міцність пружини (зазвичай її називають k), а C1 - коефіцієнт демпфування (зазвичай її називають "B" або "c"). Так, так, ви можете звести до мінімуму коливання, стягнувши амортизацію, але проблема полягає в тому, що це не намагається передбачити, де буде мета , тому приречена відставати від бажаної мети.
dash-tom-bang

3

Що у вас тут є основна проблема управління . Вежа - це система, прискорення - це управління, а датчик вимірює положення / швидкість. Існує багато способів вирішення цих проблем, оскільки це дуже добре вивчена проблема в техніці.

Ключ закінчується стабільною системою, тобто системою, яка не створює коливань. Зазвичай це робиться шляхом додавання демпфування. Сторінка вікіпедії повинна розпочати роботу.


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 (тобто прискорити і уповільнити), щоб отримати той же результат.


Це виглядає як хороша відповідь для розрахунку перехоплення, але, на жаль, існує великий розрив між людьми, які можуть прочитати таку математичну нотацію і перетворити її в програмний код, і більшість людей, які роблять ігри, які ще не знають відповіді на питання. Іншими словами, я думаю, що ігрові розробники, які можуть прочитати цю математичну нотацію, напевно, вже можуть зрозуміти, як запрограмувати розпалювальне рішення. Це допоможе мені зрозуміти ваші формули, якби ви пояснили, що означають ваші терміни.
Дронз


0

Перше, що потрібно зробити - це обчислити кут між потоком і відстежуваним об'єктом.
Наступне - перевірити, чи використовуючи поточну швидкість торрента та застосувавши максимальне прискорення назад (зупиняючи торрент), торрент зупиниться до або після відстежуваного об’єкта.
Якщо відповідь полягає в тому, що торрент зупиниться перед гусеничним об'єктом, застосуйте максимальне прискорення вперед (збільшуючи швидкість).
Якщо відповідь полягає в тому, що торрент зупиниться після відстежуваного об'єкта, застосуйте максимальне прискорення назад (зупиняючи торрент).
Таким чином торрент завжди буде прибувати найшвидше і зупиниться в потрібній точці (або на частку після).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.