Спершу потрібно визначити різницю кута між напрямком повернення башти та напрямком до цілі.
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
( в межах стабільних кордонів).