今回は、画面を動かした。ソースコードはこちら。
#いつ画面更新するか
GBは、1/60秒ごとにVRAMの内容を画面に表示する。その処理は、1/60秒間ずっと続いているわけではなく、実際は少し短い。そのため、画面表示の処理をしていない、「すきま時間」が存在している。プログラムは、その「すきま時間」に、VRAMを書き換えるような画面更新処理を実行する必要がある。
この「すきま時間」は、ブラウン管テレビの用語の名残で「垂直帰線区間」や「VBlank」等と呼ばれるようである。本記事でも「VBlank」と呼ぶことにする。
#VBlankとの同期
画面を更新するためには、VBlankの間にVRAMを書き換えたい。だが、VBlankがいつ発生するかを知る方法が必要である。
GBでは、VBlankが開始したタイミングで割り込み発生するので、それをハンドルすればよい。具体的には、VBlankが発生すると$0040番地に処理が飛ぶので、そこに画面更新のルーチンを記載すればよい。ただし、そこには8バイトしかプログラムが書けないので、画面更新のルーチンにジャンプする命令を書くことになるだろう。
#メインループの書き方
gpspec.txtでは、以下のような構成のメインループが提案されていたので、そうした。プロの方が書いた記事でも、そのような構成は現場で使われていたとある。
VBlank割り込みハンドラ:
- VBlankフラグをセット
メイン処理:
- VBlankフラグがセットされるまでループ
- VBlankフラグをクリア
- ゲームの処理
;VBlank割込みハンドラ
draw:
ld a,1
ld [VBlankFlg],a
reti
;メインループ
mainloop:
halt ;何らかの割り込みが発生するまで、CPU(?)を止める。電池節約のために良いとされる。
nop ;halt命令で処理が止まる前に,次の命令が実行されてしまうので、ダミーの1命令を挟む
;Vblankを含め、何らかの割り込みがあった場合、ここに来る
ld a,[VBlankFlg] ;VBlank割り込みハンドラがフラグを立てたかチェック
or a
jr z,mainloop ;(つまり、今回の割り込みがVBlank割り込みであれば次に進む)
xor a ;a=0
ld [VBlankFlg],a ;VBlank判定用のフラグをクリア
;[メインの処理]
jp mainloop
割り込みハンドラにあまり多くの処理を書くのはよくないのかもしれない。