レイフォースという昔のシューティングゲームでは、通常ショットの他にロックオンレーザーという武器を使って攻撃する。 ロックオンした数に応じてスコアが倍々になるという爽快感と、ロックを貯めてる間は敵が生きているため攻撃されるリスクとのジレンマという戦略性の楽しみがあった。

ということはさておき、ロックオンレーザーのホーミング挙動を再現したい。
前口上
レイフォースはプレイ・グラフィック・ストーリー・サウンド・演出どれもよくできていて不朽の名作だ。 その中でも一番の特徴としてロックオンレーザーがある。 ロックオンレーザー(以降レーザー)はゲームプレイの戦略そのものに関わっていて、ゲームの中核といえる。
そんな重要度もさることながら、軌跡が綺麗でとてもそそられる。 レーザーは自機の後方からいったん後ろに向かって発射され、ターゲットに一直線に向かうのではなく曲線を描いて回り込むように動く。 この挙動がとても綺麗でどう動いているのかが興味深く不思議だった。
どうにか挙動を再現できないかと目コピであれこれ適当に自分で計算式をいじってみたけど全然ダメだった。 なんとか挙動を再現すべく、最終手段としてアーケード基板のバイナリを解析することにした。
解析結果
あれこれ解析した結果、ある程度挙動を把握できた。基本的な情報:
- 画面解像度:
240x320 - フレームレート:
60固定 - ゲーム内座標系:XYZ=右上奥、画面中心が
XY(0, 0) - 角度:一周
256で管理 - 透視投影:視点が
(0,0,-256)からZ+方向に見て、Z=0が画面上で等倍となる画角
発射時:初期速度
- 初期角度:開始角度+増分*インデックス(例:8本同時発射の場合
0x16 + 0x0c * i) - 初期仰角:
0xa0(Z方向に上昇方向に初期の向きが設定される) - 初速:
18 - 複数ロックは1フレームずつずらして発射される
ホーミングの挙動
大まかにいうと「ターゲット方向に向かう目的速度と現在の速度との線形補間」になる。 具体的には現在の位置\(\vec{p}\)からターゲット位置\(\vec{q}\)へのベクトルを\(\vec{d} (= \vec{q} - \vec{p})\)とすると、新しい速度は
$$ \vec{v}_{new} = \vec{v} + \left( c \cdot \frac{\vec{d}}{|\vec{d}|} - \vec{v} \right) \cdot \alpha $$
となる。
\(c\) が目的速度(レイフォースでは48)、\(\alpha\)がブレンド率
(一定ではなく発射から12フレームは1/16、それ以降はXYが1/32、Zが1/64)。
- 実際のコードではベクトルの正規化ではなく角度を求めた上でサイン・コサインをテーブル参照で求めて算出
着弾
- ターゲットとの距離が12ピクセル未満になった場合、着弾と判定される
- 着弾後はよりターゲット位置に収束する挙動に変更: \(\vec{v}_{new} = \vec{v} + \frac{1}{2} (\frac{1}{2}\vec{d} - \vec{v}) \)
- 14フレーム後に終了
離脱
- 着弾までの間に自機が死んだり敵がショットで破壊された場合、ターゲットからそれる挙動になる
- 目的の角度にランダムの値がセットされる
- 画面外になって11フレームで終了
空撃ち時
- ロックしてない状態でボタンを押すと空撃ちで発射される
- 発射時にターゲット座標が
(発射時の自機X, 0xa00, 0x40)、初期角度にランダムに-3~+4、仰角が0x7c固定 - 発射後の挙動はホーミングと同じ
デモ
- 長押し→リリースでロックオン発射、クリックで空撃ち
- シフトキー押しながらで自機移動、QZでターゲット高低移動
- ホーミング中にXで離脱
- Pでポーズ(トグル)、Sでステップ実行
あとがき
- 案外シンプルなアルゴリズムであった…これを推測できない己が悲しい
- 実際のコードでは固定小数点8ビットで扱っているが、現代ではなんも考えずに浮動小数点数を使える…気楽なもんだ
- 2点間の角度と距離の算出:64x64で角度と距離が各1バイトのテーブル参照
- R-GRAY2の挙動も調べたいね