アクション系ゲームのキャラクタ移動など、1ドット単位よりも細かな座標指定を擬似的に扱うにはどうすればよいのでしょうか。ストレートに考えれば、小数点を変数に持たせることが必要になると思います。そこでfloat型を使用して・・・となりますが、ちょっと待ってください。浮動小数点の取扱いはCPUの処理に時間が掛かり、整数計算の数十倍は時間が掛かるといわれています。実は整数型を使った良い方法があるのです。方法は単純で256を1ドット分とみなすようにするだけです。この決まり事を事前にプログラム上の約束にすることで「座標 % 256」という結果の「0~255までの値」を小数として利用できます。
10進数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ... | 254 | 255 | 256 |
16進数 | 0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF | 0x10 | ... | 0xFE | 0xFF | 0x100 |
内訳としては、
typedef struct { u16 x; u16 y; } ST_WORD; typedef struct { u8 xl; u8 xh; u8 yl; u8 yh; } ST_BYTE; typedef union { ST_WORD w; ST_BYTE b; } ST_CHR_POS;
unionを使用していることで、たとえばST_WORD にx=16384、y=32768 が格納されていたとします。次にST_BYTE のxh, yh(上位ビット) を見ることで、表示座標の64、128を求めることが可能になります。
ST_CHR_POS chr; chr.w.x = 16384; chr.w.y = 32768; DispChr(chr.b.xh, chr.b.yh);
1/256精度もあれば、大抵は実用に耐えると思います。ところが精度は半分でもいいから、画面外処理のために移動範囲を余裕に持ちたい、ということなら「128を1とみなす」ようにしても良いでしょう。さらにST_WORDやunionを使用せずu16だけを使い、表示座標がほしいときだけ「座標>>7」に変換するだけでもかまわないと思います。
IWRAM_CODE u8 ChrGetTransPos(u16 src) { return src >> 7; }
GBAならイチオシの使い方なので、よかったら使用してみてください。ただし最近のCPUなどでは、double型を直接使用したほうが有益とされています。何故有益かというと、整数と小数の速度の差異自体、もはや気にするレベルでは無いですし、こっちの方が正確だし、組んでていちいち256を意識する必要が無いからです。