スプライトをアニメーション表示にする(手動制御)
スプライトにアニメーションフレームを設定し、フレームを切り替えてアニメーション表示を行います。
- 2022-11-15
- 公開
コード
res_image.res
- PALETTE tire_palette "tire.png"
- SPRITE tire_sprite "tire.png" 4 4
main.c
- #include <genesis.h>
- #include "res_image.h"
- #define BUTTON_REPEAT_TRIGGER_COUNT 0
- #define BUTTON_REPEAT_INTERVAL 5
- #define NUM_OF_ANIMATION 3
- /**
- * コントローラの状態
- */
- typedef struct {
- u16 current; // 押下しているキー
- u16 trigger; // 押し始めたキー
- u16 off; // 離したキー
- u16 repeat; // 押し続けているキー
- u16 repeatCount; // リピートカウント
- } JoyState;
- /**
- * コントローラの状態を保持するグローバル変数
- */
- JoyState joyState;
- /**
- * コントローラ状態の初期設定
- */
- static void joyInit() {
- // 初期化(0埋め)
- memset(&joyState, 0, sizeof(JoyState));
- }
- /**
- * VBlankごとに1回だけボタンの情報を取得する
- */
- static void joyExec() {
- u16 state = JOY_readJoypad(JOY_1);
- joyState.trigger = state & ~joyState.current;
- joyState.off = joyState.current & ~state;
- joyState.current = state;
- // 「押し続けているキー」の設定
- // NOTE: 「押し続けているキー」は、押し始めたあと指定の時間無効化され、
- // それ以降押下している間は一定の間隔でオンオフを繰り返す
- if (joyState.trigger) {
- joyState.repeat = joyState.current;
- joyState.repeatCount = BUTTON_REPEAT_TRIGGER_COUNT;
- }
- else if (!joyState.repeatCount) {
- joyState.repeat = joyState.current;
- joyState.repeatCount = BUTTON_REPEAT_INTERVAL;
- }
- else {
- joyState.repeat = 0;
- }
- // カウント
- if (joyState.current) {
- if (joyState.repeatCount > 0) {
- joyState.repeatCount--;
- }
- }
- }
- int main(u16 hard) {
- // タイルのVRAM位置
- u16 index = TILE_USERINDEX;
- // コントローラ状態の初期化
- joyInit();
- // 色の設定
- PAL_setPaletteColors(0, &tire_palette, DMA);
- // スプライトエンジンの初期化
- SPR_init();
- // スプライトの追加と取得
- Sprite* tire = SPR_addSprite(&tire_sprite, 144, 88, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, index));
- // 操作説明テキスト
- VDP_drawText("A Button:Next Frame", 9, 17);
- VDP_drawText("B Button:Next Animation", 9, 18);
- // メインループ
- while (TRUE) {
- SYS_doVBlankProcess();
- // ボタン状態取得
- joyExec();
- if ((joyState.trigger & BUTTON_A) || (joyState.repeat & BUTTON_A)) {
- // スプライトのフレームを1つ進める
- SPR_nextFrame(tire);
- }
- if (joyState.trigger & BUTTON_B) {
- // スプライトのアニメーションを次のセットにする
- SPR_setAnim(tire, (tire->animInd + 1) % NUM_OF_ANIMATION);
- }
- // スプライト更新(スプライトに対して行った変更が反映される)
- SPR_update();
- }
- return 0;
- }
実行結果
上記コードをSGDK1.70でコンパイルし
Gens v2.14 Souvenirで実行したスクリーンショット
解説
画像
スプライトをアニメーション表示にするためには、表示したいフレーム分のイメージを設定した1枚画像を用意します。
今回使用した画像で説明します。
アニメーションスプライトは「animation」セットの中にそれぞれの「frame」を持った構造になっています。
画像の横に並んだ部分が1つのアニメーションセットとなり、そのセットを等間隔で分割したフレームが1枚ずつ表示されることによりアニメーション表示となります。
今回の画像では以下のようなアニメーションスプライトになります。
2フレームのアニメーションセット0、4フレームのアニメーションセット1、4フレームのアニメーションセット2です。フレーム数は異なっても問題ありません。透明色のみのフレームは無視されます。
ResComp
画像を用意したら、次はResComp1のためのresファイルの設定です。今回使用したresファイルのスプライト部分の各項目の意味は以下になります。
- SPRITE
- リソース種別
- tire_sprite
- スプライト名
- "tire.png"
- 画像のパス
- 4
- 幅(タイル数)
- 4
- 高さ(タイル数)
ここで設定した幅と高さで対象画像が分割され、アニメーションデータとして格納されます。
VRAM
スプライトで使用するタイルは、自動でVRAM2にアップロードするかしないかを設定できます。
自動アップロードが有効の場合はフレームが切り替わるたびにVRAMの該当位置にあるスプライトタイルが置き換わります。
無効の場合は手動でスプライトタイルをVRAM上にアップロードし、フレームを切り替える際にそのタイル位置を指定する必要があります。
VRAMに保持出来るデータ量(タイル数)には制限があるため、表示する画面によっては自動アップロードの有効無効を上手く切り替える必要があるでしょう。
画面上に1つしか存在しないスプライト(操作する主人公など)は有効に、複数登場するスプライト(雑魚敵など)は無効にするのが切り替えの基準になるかもしれません(参考: ガンスターヒーローズのVRAM使用状況(記事中盤の動画))。