アクション系ゲームのキャラクタ移動など、1ドット単位よりも細かな座標指定を擬似的に扱うにはどうすればよいのでしょうか。ストレートに考えれば、小数点を変数に持たせることが必要になると思います。そこでfloat型を使用して・・・となりますが、ちょっと待ってください。浮動小数点の取扱いはCPUの処理に時間が掛かり、整数計算の数十倍は時間が掛かるといわれています。実は整数型を使った良い方法があるのです。
方法は単純で16を1ドット分とみなすようにするだけです。この決まり事を事前にプログラム上の約束にすることで「座標 % 16」という結果の「0~15までの値」を小数として利用できます。このことは16進数でいう4bit分、つまりs16だと下位4ビット=小数点、上位12ビット=実際の表示ピクセル座標という扱いになります。
10進数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 省略・・・ |
16進数 | 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF | 0x10 | 0x11 | 0x12 | |
2進数 | 0 | 1 | 10 | 11 | 100 | 101 | 110 | 111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 | 10000 | 10001 | 10010 |
s16 x, y; // 座標の代入 x = ((GBAの横サイズ240 / 2) - (キャラサイズ / 2)) << 4; y = ((GBAの縦サイズ160 / 2) - (キャラサイズ / 2)) << 4; // 座標の加算 x = x + 1; // 座標の表示 SpriteDraw(x >> 4, y >> 4);
%は動作が重いため、シフト演算を使っています。
int main(void) { REG_WSCNT = 0x4317; BgInit(); IrqInit(); KeyInit(); SprInit(); SpriteSetAlpha(); char strX[32], strY[32], strM[32]; u16 cnt; s16 x = ((240 / 2) - (8 / 2)) << 4; s16 y = ((160 / 2) - (8 / 2)) << 4; s16 m = 25; for(;;) { VBlankIntrWait(); KeyExec(); cnt = KeyGetCnt(); if(cnt & KEY_UP ) y-=m; if(cnt & KEY_DOWN ) y+=m; if(cnt & KEY_LEFT ) x-=m; if(cnt & KEY_RIGHT) x+=m; if(cnt & KEY_R ) m+=1; if(cnt & KEY_L ) m-=1; if((x>>4) < 0) x = 0; if((x>>4) >= 240-8) x = (240-8) << 4; if((y>>4) < 0) y = 0; if((y>>4) >= 160-8) y = (160-8) << 4; if(m <= 0) m = 1; if(m >= 50) m = 50; SpriteMoveAlpha(x>>4, y>>4); _Sprintf(strX, "x:%3d %4d 0x%04x", x>>4, x, x); _Sprintf(strY, "y:%3d %4d 0x%04x", y>>4, y, y); _Sprintf(strM, "m:%3d", m); BgAsciiDrawStr(0, 17, strX); BgAsciiDrawStr(0, 18, strY); BgAsciiDrawStr(0, 19, strM); } }