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