これは、 Luaスクリプトでbox2dをカバーするLÖVEエンジンを使用してゲームを実装しようとしたときに発生した問題です。
目的は単純です。砲塔のようなオブジェクト(2D環境で上から見たもの)は、ターゲットを指すように向きを変える必要があります。
タレットはx、y座標上にあり、ターゲットはtx、ty上にあります。x、yは固定されていると考えることができますが、tx、tyは瞬間ごとに変化する傾向があります(つまり、マウスカーソルになります)。
タレットにはローターがあり、時計回りまたは反時計回りの任意の瞬間に回転力(トルク)を加えることができます。その力の大きさには、maxTorqueと呼ばれる上限があります。
タレットには一定の回転慣性もあり、質量が線形運動に作用するのと同じように角運動に作用します。いかなる種類の摩擦もないので、角速度があれば砲塔は回転し続けます。
タレットには小さなAI機能があり、その向きを再評価して正しい方向を指していることを確認し、ローテーターをアクティブにします。これはdtごとに発生します(1秒あたり約60回)。今はこんな感じです:
function Turret:update(dt)
local x,y = self:getPositon()
local tx,ty = self:getTarget()
local maxTorque = self:getMaxTorque() -- max force of the turret rotor
local inertia = self:getInertia() -- the rotational inertia
local w = self:getAngularVelocity() -- current angular velocity of the turret
local angle = self:getAngle() -- the angle the turret is facing currently
-- the angle of the like that links the turret center with the target
local targetAngle = math.atan2(oy-y,ox-x)
local differenceAngle = _normalizeAngle(targetAngle - angle)
if(differenceAngle <= math.pi) then -- counter-clockwise is the shortest path
self:applyTorque(maxTorque)
else -- clockwise is the shortest path
self:applyTorque(-maxTorque)
end
end
...失敗します。2つの実例となる状況で説明させてください。
- タレットはtargetAngleの周りで「振動」します。
- ターゲットが「タレットのすぐ後ろ、時計回りに少しだけ」の場合、タレットは時計回りのトルクを適用し始め、ターゲットの角度を超える瞬間までそれらを適用し続けます。その瞬間、それは反対方向にトルクを加え始めます。しかし、それはかなりの角速度を獲得しているので、しばらくの間時計回りに進み続けます...ターゲットが「すぐ後ろですが、少し反時計回り」になるまで。そして、それは再び始まります。そのため、砲塔は振動するか、丸い円を描くことさえあります。
私の砲塔は、目標角度に達する前に「最短経路の反対方向」にトルクを加え始める必要があると思います(停止する前に車がブレーキをかけるように)。
直感的には、砲塔は「目標目標のほぼ半分になったら、最短経路の反対方向にトルクをかけ始める」べきだと思います。私の直感は、それが角速度と関係があることを教えてくれます。そして、ターゲットがモバイルであるという事実があります-どういうわけかそれを考慮に入れるべきか、それとも単に無視するべきかはわかりません。
タレットが「ブレーキをかけ始める」必要がある時期を計算するにはどうすればよいですか?