前回は、画面を使用しなかったのですが、これでは全く面白くないので、絵を出してみました。GBは背景画面の上にスプライトと呼ばれる動く画像を重ねて表示する(多分。まだちゃんと調べてない)。今回は、背景画面の方を試してみました。
ソースコードはこちら。
#GBの画面表示の仕組み
##タイル
- ゲームボーイの背景画像は、タイルと呼ばれる8X8ピクセルの画像を並べることで構成されている。
- タイルの画像は、VRAMに書き込む。(ROMから必要に応じてコピーする)
##背景画面の構成
- サイズは、32タイル×32タイルである。VRAM上では、タイルの番号が1バイトごとに書き込まれている。
- 背景画面は、実際の画面より大きい。SCRXレジスタとSCRYレジスタに、「背景画面のどこを、画面表示の起点(左上)にするか」を指定する。なお、このレジスタを変化させることで、スクロールが実現できる。
#初期化の流れ
パレットとスクロールレジスタを設定する。
ld a, %11100100 ; パレット(パレットごとに2bitで白さを指定。MSBがパット番号0番)
ld [rBGP], a ; BGPレジスタにパレットを設定
ld a,0 ; スクロールレジスタを設定し、画面を左上に固定
ld [rSCX], a ; SCXレジスタ
ld [rSCY], a ; SCYレジスタ
画面の描画中はVRAMへの書き込みが行えないので、一旦画面の表示をオフにする。
.waitVBlank: ; 画面描画を止めるため、まず現在の描画が終るのを待つ
ld a, [rLY]
cp 145 ; 画面描画が終った=描画位置がY=145であるか?
jr nz, .waitVBlank ; 違ったらまだ待つ(jrは相対ジャンプで、命令長が短くなる)
ld a, [rLCDC]
res 7, a
ld [rLCDC], a ; VRAMに書き込むため、画面描画を止める
タイルをVRAMにロードする。
ld hl, Tile ; vramcpy コピー元 (ハードコードしたタイルの画像のアドレス)
ld bc, _VRAM ; vramcpy コピー先 ($8000)
ld de, TileEnd-Tile ; vramcpy コピー長さ
call vramcpy ; VRAMに値をコピーするするサブルーチン
VRAMにタイル番号を設定する。
ld b, $0 ; vramset 設定値
ld hl, _SCRN0 ; vramset コピー先
ld de, 32*32 ; vramset コピー長さ
call vramset ; サブルーチン。画面全域にタイル番号0番を設定
画面の描画を再開する。GBには背景画面が2つあり、今回は「BG8000」を使用しているため、LCDCレジスタに「LCDCF_BG8000」をセットしている。また、タイルも2セットVRAMに持つことができ、今回は「BG9800」を使用している。スプライトを使用しないため、「LCDCF_OBJOFF」で表示をオフにしている。
ld a, LCDCF_ON|LCDCF_BG8000|LCDCF_BG9800|LCDCF_BGON|LCDCF_OBJ16|LCDCF_OBJOFF
ld [rLCDC], a ; 画面ON
メインループ開始
mainloop:
halt
nop
jr mainloop
#タイルのフォーマット
タイルのデータフォーマットは、なかなかにトリッキーである。今回使ったこのタイル(パレット番号0が白、1が明るい灰、2が暗い灰、3が黒)の場合、
下のような形でピクセルごとにパレットの番号を指定する。
;タイル用画像
;2バイトで1ラインを表し、各バイトの各ビットが1ピクセルに対応する。
;偶数バイトが、パレット番号の下位ビットを表し、奇数バイトが上位ビットを表す
Tile:
;1行目8ピクセルのパレット番号は, 0,3,3,3, 3,3,3,3
db %01111111 ;1行目, パレット番号下位ビット
db %01111111 ;1行目, パレット番号上位ビット
;2行目8ピクセルのパレット番号は, 2,2,2,2, 2,2,2,2
db %00000000 ;2行目, パレット番号下位ビット
db %11111111 ;2行目, パレット番号上位ビット
db %11111111 ;3行目
db %00000000
db %00000000 ;4
db %00000000
db %11111111 ;5
db %00000000
db %00000000 ;6
db %11111111
db %11111111 ;7
db %11111111
db %00000000 ;8
db %00000000
TileEnd:
手で書くのはとても辛いので、下のようなツールがある。アセンブラのソースにそのままインクルードできるコードを出力してくれる優れものだ。
http://www.devrs.com/gb/hmgd/gbtd.html