Chapter.15 敵と自機弾の当たり判定、高速化
[Chapter15 制作物]

今回は、敵と自機弾の当たり判定処理を作ります。ついでに自機のあたり判定も作りますが、まだメインループに組み込みません。
ついでに処理の高速化もやります。

■敵と自機弾の当たり判定




工事中




■高速化1
sca_sprite.asm の sprite_update を見てください。
最初に「2枚重ねスプライトの2枚目の座標を1枚目と重ねる」というコメントが記入されている部分です。
プログラム1 にその部分を示します。

プログラム1 二枚重ねスプライトの二枚目の処理
sprite_update::
		; 2枚重ねスプライトの2枚目の座標を1枚目と重ねる
		ld		de, #SCA_INFO_SIZE
		push	ix
		ld		b, #7		; 自機、敵6機で、合計 7機
sprite_update_adjust:
		ld		a, SCA_INFO_XL(ix)
		ld		SCA_INFO_XL2(ix), a
		ld		a, SCA_INFO_XH(ix)
		ld		SCA_INFO_XH2(ix), a
		ld		a, SCA_INFO_YL(ix)
		ld		SCA_INFO_YL2(ix), a
		ld		a, SCA_INFO_YH(ix)
		ld		SCA_INFO_YH2(ix), a
		add		ix, de
		add		ix, de
		djnz	sprite_update_adjust
		pop		ix
		


各キャラクタ(自機とか敵とか弾とか)の情報を集めているメモリを SCA_INFO と呼んでますが、
2枚重ね表示をするスプライト(自機、敵)は、それを2つ分持ってます。
この2つ目の方の座標を、1つ目の方の座標と同じにする処理です。
わざわざ1つ目の座標を読み出して、2つ目に書き出してます。

しかし、1つ目の座標を書き込むとき、座標はレジスタにあるはずです。
従って、1つ目の座標を書き込むときに、ついでに2つ目にも書いてしまえば、「コピーするために読み出す」という処理
が不要になります。
しかも、プログラム1の処理が不要になります。

de レジスタの値は次以降でも使っているので、ld de, #SCA_INFO_SIZE の部分を残して、プログラム1 の部分は削除してしまいます。

次に、「1つ目の座標を書き込むときに、ついでに2つ目にも書いてしまう処理」を、自機と、全種類の敵にたいして記述
していかなければなりません。

自機なら、sca_player.asm の player_move にある SCA_INFO_XH(ix), SCA_INFO_YH(ix) への LD 命令の次の行に
SCA_INFO_XH2(ix), SCA_INFO_YH2(ix) に同じ値を LD するように追記します。
敵も同様です。

■高速化2
sca_background.asm の background_scroll を見てください。
call SETWRT は、VDP に対して「これから書き込む VRAMアドレスをセットする」という BIOSエントリですが、
background_scroll_loop2 のループの内側に記述されています。

background_scroll_loop2 のループは、
 1回目は 40,41,42,43 のキャラクタフォントを書き換える処理、
 2回目は 44,45,46,47 のキャラクタフォントを書き換える処理、
 3回目は 48,49,50,51 のキャラクタフォントを書き換える処理、
 4回目は 52,53,54,55 のキャラクタフォントを書き換える処理、
になっています。
1回目の最後の次が、2回目の最初になっているので、キャラクタフォントの VRAMアドレスは連続しています。
従って、background_scroll_loop2 の前に1度だけ call SETWRT すれば、問題ないわけです。

ということで、call SETWRT を background_scroll_loop3 の pop bc の下へ移動します。

■高速化3
またスクロールです。
background_scroll は、背景を1ドットスクロールさせる処理ですが、呼ばれるたびに必ずスクロールしてます。
試しに、background_scroll の入り口で ret して、ビルド・実行してみてください。

動作が爆速になるのを確認出来たと思います。
つまり、動作が遅い原因は、このスクロール処理に時間がかかっているからだと言えるわけです。

ここの処理を間引くことで高速化できます。

背景は4回に1度だけ1ドットスクロールするように変更します。
background_scroll の入り口に、プログラム2 を挿入します。
さらに、スクロールカウンタのところに、プログラム3 を挿入します。

プログラム2 4回に1回を判断する処理
		; スクロールするタイミングか?
		ld		a, (background_scroll_timing)
		dec		a
		and		#3
		ld		(background_scroll_timing), a		; ※フラグ不変
		ret		nz
		


プログラム3 4回に1回を判断する処理用のワーク変数
background_scroll_timing:
		.db		#0				; 0〜3, デクリメントカウンタ
		


プログラム2 は、ワーク変数 background_scroll_timing に対して、次のような計算をしてます。

background_scroll_timing = (background_scroll_timing - 1) AND 3

これは、3,2,1,0,3,2,1,0 ・・・ という値を繰り返すようになってます。
and #3 のところで、ゼロになったときだけ Zフラグが立つので、4回に1回であるかの判断に Zフラグが使えるわけです。

ret nz は、Zフラグが立っていない場合だけ呼び出し元へ戻る命令です。


ここまでで、だいぶ速くなりました。
速くなりすぎる分には、あとでどうにでも調節できます。
そのあたりは、次回に。


[▲トップページへ]