固定小数点

アクション系ゲームのキャラクタ移動など、1ドット単位よりも細かな座標指定を擬似的に扱うにはどうすればよいのでしょうか。ストレートに考えれば、小数点を変数に持たせることが必要になると思います。そこでfloat型を使用して・・・となりますが、ちょっと待ってください。浮動小数点の取扱いはCPUの処理に時間が掛かり、整数計算の数十倍は時間が掛かるといわれています。実は整数型を使った良い方法があるのです。方法は単純で16を1ドット分とみなすようにするだけです。この決まり事を事前にプログラム上の約束にすることで「座標 % 16」という結果の「0~15までの値」を小数として利用できます。このことは16進数でいう4bit分、つまりs16だと下位4ビット=小数点、上位12ビット=実際の表示ピクセル座標という扱いになります。

10進数0123456789101112131415161718省略・・・
16進数0x00x10x20x30x40x50x60x70x80x90xA0xB0xC0xD0xE0xF0x100x110x12
2進数01101110010111011110001001101010111100110111101111100001000110010
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);
	}
}

動作画面

出典元

履歴


トップ   一覧 検索 最終更新   ヘルプ   最終更新のRSS