まず、砲塔に面する方向とターゲットの方向の角度の差を決定する必要があります。
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;
これらの数量を取得したら、タレット角度の2次式を設定できます。更新のたびにこれを計算して、常に位置と速度の最新データを使用するようにする必要があります。
// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;
ここでは、加速式の最初の項(ゼロ度)により、砲塔が目標に向かって回転し始めます。ただし、時間内に停止するのではなく、前後に振動します。停止させるには、高い回転速度に高い加速度が逆行する原因となる減衰第2項(1次)が必要です。
システムが適切に動作するように、正の定数(必ずしもプログラム定数である必要はありません)を決定し、バランスを取る必要があります。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
(安定した境界内)。