ニセ比例航法

この間(id:propella:20050703)、propellaさんのところでちょっとだけお話しした比例航法を応用した「相手を追いかける」計算式をまとめました。正しい比例航法とはちがうっぽいの(そもそも、相手の移動量とかは見てない。純粋追尾航法ってのが近いのかな?)で、ここでは「ニセ比例航法」と名付けています。


まず、以下の形で変数を定義します。

  • Vd
    • 主体が今向いている方向のベクトル(必ず正規化する)
  • Vg
    • 追いかける相手の位置ベクトル
  • Vp
    • 主体の位置ベクトル
  • s
  • r
    • 誘導係数。0:誘導しない,1:常に相手の方向を向く(スカラー)

このとき、s,rは係数として処理の中では変化しません。
その上で1フレームごとに以下の処理を行います。

  1. 一時的な変数Vに Va-Vp を代入
  2. Vを正規化
  3. Vdに対し r*Vd+(1-r)*V を代入
  4. Vdを正規化
  5. Vpに対し Vp+s*Vd を代入

これだけで、かなりきれいな軌跡を描いて相手の方に向かってくれます。ミソはrの値の設定です。0から1までの値のいずれかを入れれば曲率がおおむね求まります。たとえば、1/2の時の最大変化角度が直角です。
便利なのは相手(Vp)が動いていてもいずれたどり着くところです。なので、相手の移動速度よりもsが大きければ、必ず当たるホーミングミサイルとしても使えます。
たとえば、Vdをランダムに振った上で一つの相手を狙い、さらに1フレームごとに「煙」をプロットするとそれはそれはきれいな「板野ミサイル」ができあがります(笑)。
また、描画するときに座標変換用のアフィン変換行列を作る必要がありますが、これに関しては極座標(角度)を使用せずに、upベクトル(0,1,0)とVdを元に外積2回で回転成分を作る形で対応します。極座標と直交座標を計算時に混在させると、sinテーブルやasinテーブルの精度の関係でちょっとがくがくするので、できればどちらかに統一しておいた方が何かと便利です。


ただ、以下のことに気をつける必要があります。

  1. Vを正規化するときに、0ベクトルになる可能性があり得る(座標が同じ時)
  2. Vdが変化しないことがあり得る(Vd-Vが0。つまり、ちょうど反対方向の時)
  3. Vdを正規化するときに0ベクトルになる可能性があり得る(ちょうど反対方向で、rが1/2の時)
  4. Vdを正規化するときに、1フレーム前のVdと大幅に変化する可能性があり得る(ちょうど反対方向で、rが1/2より大きい時)

例外処理が増えるのはちょっとうれしくないのですが、1フレームの間の処理がシンプルなのはいろいろと便利です。


……ってのを、つい最近とあるネットゲームやとある3Dフライトアクションゲームでまさに使いました。あまりのシンプルさに、コーディングを行ったスタッフに「ホントにこれでうごくんですか?」とか聞かれましたが(^^;)、見た目は予想以上にそれっぽくなります。おためしあれ。