真っ直ぐ飛ばすレーザーなら簡単なんですが、ホーミングやカーブは若干面倒。
どちらにしても、回転機能が無いハードで実装する場合、先ずは回転パターンを作画します。
↓こんな感じで。
普通の弾を飛ばすアルゴリズムでそのまま実現できます。
ちなみに、SHOT04(NOKOGI Rider)の敵弾は、1発毎に下図の構造体で情報を管理しています。
(1) レーザーを目標物(自機等)に向かってホーミングさせる
(2) レーザーをカーブさせる
といったことが実現できません※。
※正確には、不可能では無いけど複雑になり過ぎて処理効率が悪い
上記(1)や(2)を実現するには、トレースというアルゴリズムを実装する必要があります。
トレースというのは、一番先頭のオブジェクト(リーダー)の動作情報(ログ)を記録しておき、サブオブジェクト(メンバ)は一定間隔過去のリーダーのログと同じ動作をする・・・というアルゴリズムです。
分かり難いですね・・・分かり易く言うと、
・ドラクエのパーティーの動き
・グラディウスのオプションの動き
・インストーラーがプログラムのインストールに失敗した時に、インストール前の状態に戻す動き
・データーベースでコミット済みの状態を変更前の状態に戻す動き(ロールバック)
などなど。
これらは皆、同じトレースです。
インストーラやデータベースのロールバックはバックトレース(ログを逆順に追跡)ですが、本質は同じ事。
で、トレースを実現するのには、ログ(ジャーナルともいう)が必要。
現状の敵ショットのメンバにログを持たせても良いですが、そうなるとメモリ効率が悪いし、メモリ効率を良くすると処理効率が悪い・・・つまり、別テーブルで管理するのがベストです。
とりあえず、下図のような感じのテーブルを追加。
あと、ログはリングバッファで管理(256フレーム分)。
それで足りるかは不明。
事前に設計できなくも無いけど、作ってから調整。
ちなみに、リングバッファの場合、インデクスの加算処理で無駄な分岐によるパイプラインハザードを抑える為、要素数は2のn乗にする必要があります。(そうすることで、AND演算だけで限界時のループができるので)
【追記】
プログラムを作成してみました。
表示したみたところ、下図のような感じ。
ちなみに、テーブルの内容は結構変えました。
移動速度のログは残さない(加速しない)仕様にして、後は座標を最大の長さ分保持したり云々。
↓こんな感じで。(当初想定よりも大分シンプル)
/* 敵レーザー */ struct ELaser { int flag; /* フラグ兼フレームカウンタ */ int ix; /* 初期X座標 */ int iy; /* 初期Y座標 */ short fx[32]; /* X座標(*8) */ short fy[32]; /* Y座標(*8) */ int len; /* 現在の長さ */ int maxL; /* 最大の長さ */ int R; /* 先端のラジアン値(0~627) */ unsigned char S; /* 速度(1~15) */ unsigned char itR; /* ラジアン値の変更間隔(フレーム数) */ unsigned char addR; /* ラジアン値の角度増減量 */ unsigned char typeR; /* ラジアン値の変更方法(0:変更しない, 1:右回転, 2:左回転, 3:ホーミング) */ short logR[512]; /* 角度ログ(512フレーム分) */ }; |
レーザーの長さはMAX=32にしておきました。
32×16=512ピクセルが最大長。これだけあれば十分。
あと、10度単位で回転パターン(36パターン)を準備したのですが、若干繋ぎ目が分かり易い・・・
ただ、これは気にならないレベルなので、まぁ良いかな。
8度単位(45パターン)にしてみようか微妙なところ。
ログのサイズは256だと足りないので、512に拡張。
速度&長さがMAXの場合に必要なログ数が32×16=512なので。
速度&長さがMAXなんて、鬼畜過ぎて使うことは無いと思いますが。
ちなみに、末尾~尻尾まで全てのレーザーが画面外アウトしたら消滅する仕様。
角度がキツ過ぎると、画面に戻ってくる場合があり、それは鬼畜過ぎるので、後で仕様変更するかも。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。