テクニック:アニメーションオブジェ

レーン内のオブジェなどの各要素は通常静止画として準備しますが、これをhdaに置き換えることでアニメーションさせることが出来ます。システムスキンでは、これを利用して判定バー上部のライティングやキー押下時の背景ライティングを行っていますが、実は通常のオブジェなどにも適用することが出来ます。
バックスピンスクラッチをアニメーションしてみる
ここではサンプルとして、以下のようにアニメーションするバックスピンスクラッチの使用方法を説明します。

※この元データは下の方でダウンロード出来ます


このアニメーションは原点を左上として、グローバル定数に指定したサイズ(OBJ_WIDTH_SCRATCHOBJ_HEIGHT)に合わせて作成されています。また、同サイズに合わせてマスクが設定されています。これにより、アニメーションが隣のレーンに干渉しないようになっています。なお、アニメーションファイルには画像サイズという概念は無いため、作成時はツール上でしっかりと最終的なサイズを把握して作成する必要があります。
※裏技として、マスクを使用せず画像をスクラッチの範囲外に置くことで、範囲外への描画も可能です

レーンの描画はシステム側で行いますが、ゲーム中もしロングが画面に収まらないほど長かった場合、自動的にタイリングで表示されるようになっています。これにより、ロングの開始から終端まで必要な分だけ、連続で繋がっているように描画されます。

例えば上のサンプルには、分かりやすくするため以下のように上下に赤と緑の線が引かれていますが、ゲーム上ではタイリングされることでこれらが繋がってスクロールしていきます。

 上部
 

 下部
 

 タイリングによるスクロール(本来は上のアニメーションのようにさらに左右に揺れます)
 




次にこれをスクリプトに定義します。
function OnInitLane()
    // ロング用スクラッチアニメーションをロード
    hdxSysLoadAnime( 10, "scratch.hda", 0, 0 );

    // ロング用スクラッチアニメーションをロング中間オブジェとして割り当てる
    hdxSysSetObject( OBJID_SCRATCH_LONGOFF_MIDDLE,  DRAWTYPE_ANIME, 10 );
end

まずはOnInitLane()関数内でスクラッチアニメーションファイルをロードします。ここではスロット10にロードしています。

次にこのアニメーションをスクラッチの中間オブジェクト(OBJID_SCRATCH_LONGOFF_MIDDLE)に割り当てます。DRAWTYPE_ANIMEとすることでこのオブジェはアニメーションスロットを参照することになり、ここではスロット10を指定することで、結果的にスクラッチのアニメーションファイルが割り当てられたことになります。

これでこのアニメーションはスクラッチ用に使用されるように設定されましたが、このアニメーションはまだ非表示で停止した状態となっているため、もし画面上にロングオブジェが現れても、このままでは中間部分は何も表示されない状態となります。

これを表示させるためにはレーン制御用に呼び出されるOnUpdateLane()内で、表示するアニメーションフレーム番号を手動で指定します。実はシステムアニメもOnInitLane()内でhdxSysSetObject()を呼び出して、始めから自動ループアニメーションを行うように設定しておくことが出来ますが、ここでは曲のテンポに合わせて左右の揺れを調整したいため、ここではこの自動再生機能は使用しないことにします。

OnUpdateLane()には現在の曲のチック数(1小節がBMS_RESOLUTION=9600となる値で、ゲームが進むとどんどんカウントアップされる)が渡されるため、これを利用することで曲とアニメーションを同期させることが出来ます。

以下は設定したスクラッチのアニメーションを行うためのコードです。
// レーンの描画の前に呼び出されるので、現在のチックを参照してレーン内で定義したアニメのフレーム値を更新する。
function OnUpdateLane( tick,delta )
    // スクラッチのフレームを算出してセット(1小節に4回ゆれる)
    local _tick = tick % (BMS_RESOLUTION / 4);                                  // 進んだチック数を0~2399に変換
    local _scale = _tick / (BMS_RESOLUTION / 4);                                // 0~2399を0.0~1.0に正規化して倍率とする
    local frm = (hdxSysGetAnimeMaxFrame(10)-1) * _scale;                        // アニメの最大フレーム数に倍率を掛けることで表示するフレーム番号を算出
    hdxSysCtrlObject( CTRLID_SCRATCH_LONGOFF_MIDDLE,0,TRUE,1.0,0,frm,0,-2 );    // フレーム番号を指定して表示

end

上記のスクラッチアニメは左右に1回だけ揺れるアニメーションを0~(最大フレーム数-1)フレームとして作成しています。そしてこのアニメのフレーム番号を現在のチック数から算出することで、その瞬間の位置で画面に表示されます。

今回は1小節中に4回揺れる(つまり1拍で1回揺れる)ような速度で表示しているため、ゲーム中では結構速く小刻みに動いているように見えると思います。

コードを解説するとまず1拍のチック数を求めるためBMS_RESOLUTIONを4で割った値を求めます。BMS_RESOLUTIONは現状9600が定義されているので、ここでは実質1拍は2400と計算されます。

次に現在のチック数を1拍単位(0~2399)に収めるために、進んだチック数から1拍分のカウント値で割ったあまりを算出します。あまりはC言語同様に「%」演算子を使用することで求めることができます。

次に0~2399を正規化し、0.0~1.0の範囲に収めるため1拍のカウンタで割っています。正規化することでこの値を倍率として使うことが出来るようになります。

最後にスクラッチアニメの最大フレーム数に現在の倍率を掛けることで、現在表示されるスクラッチアニメ内のフレーム番号を算出することが出来ます。
※スクラッチアニメの最後のフレームは制作上最初のフレームと同じ位置になっているため、そのフレームも含めてしまうとゲーム中に最初と最後のフレームが2度表示されてしまうためひっかかりを感じます。そのためここでは最大フレーム数から1フレームを引いた値をスクラッチアニメの最大フレーム数としています。

最終的に算出したフレーム番号をhdxSysSetCtrlObject()に与えることで、その時の位置でスクラッチが表示されるようになります。
hdxSysCtrlObject()に渡すフレーム番号に小数値を渡した場合は、その前後のフレームから補間した位置を算出します

この方法を応用してシステムレーン内の全ての要素(オブジェなど)をアニメーションさせることが出来るので、レーンの処理だけでもかなり凝ったものが作れると思います。
ダウンロード
ここでは上記のスクラッチアニメーションのサンプルスキンと、アニメーションメーカーV2用のワークファイルをダウンロードすることが出来ます。