第11章 BGスクロール


BG

 スプライトはひとまず終わりです。BG(BackGround/背景)に取り掛かりましょう。BGとは、 1画面全体の(ただし画面外にもう1〜3面持てる)背景データです。 スプライトのように横8つまでという制約はありません。このBGをゲーム中に上手に更新することが プログラマの腕の見せ所であり、名作といわれるゲームは総じてこのBGを巧く使っている作品が多いようです。 スプライトのような制約がないので、通常の背景だけでなく巨大な敵や大量の小さい敵を表示してみたり、 ラスタースクロールというテクニックを駆使してファミコンの表現能力の限界に挑戦しているゲームがあります。

ネームテーブル

 第5章で、BGパターンテーブルはVRAMの$0000番地から開始すると説明しました。BGパターンもスプライトと同様のフォーマットで、 8x8のキャラを256種類、4キロバイト分持つことが可能です。この256種類のキャラクターの番号を、ネームテーブルという領域に1バイトずつ指定して画面に敷き詰めます。

 第2章のメモリマップを見ると、ネームテーブル領域は4つ存在するように見えますが、普通は2つしか使えず残りはミラーとなります。ただし拡張して4つ使っているゲームも 存在するようです。今回は$2000から$3BF(960)バイト書き込むことにします。960という数は、BGのタイル数が横32x縦30=960だからです。 左上から右下という順に横方向に敷き詰めます。

 以下は例です。この場合、BGデータの0番に真っ黒なキャラ、1番と2番に星の絵が入ってるという前提です。Star_Tblは星と星の間の黒い0番の数のテーブルで、 やっていることは、ネームテーブルに黒の0番を60回書き込んで、次に1番の星を書き込んで、次は0番の黒を45個書き込んで、次に2番の星を書き込んで・・ というような処理を行っています。あんまり良い例ではないですねえ・・・。


	; $2000のネームテーブルに生成する
	lda #$20
	sta $2006
	lda #$00
	sta $2006

	lda #$00        ; 0番(真っ黒)
	ldy #$00    	; Yレジスタ初期化
loadNametable1:
	ldx Star_Tbl, y				; Starテーブルの値をXに読み込む
loadNametable2:
	sta $2007				; $2007に属性の値を読み込む
	dex					; X減算
	bne loadNametable2	; まだ0でないならばループして黒を出力する
	; 1番か2番のキャラをYの値から交互に取得
	tya					; Y→A
	and #1					; A AND 1
	adc #1					; Aに1加算して1か2に
	sta $2007				; $2007に属性の値を読み込む
	lda #$00        ; 0番(真っ黒)
	iny					; Y加算
	cpy #20					; 20回(星テーブルの数)ループする
	bne loadNametable1

	; 星テーブルデータ(20個)
Star_Tbl    .db 60,45,35,60,90,65,45,20,90,10,30,40,65,25,65,35,50,35,40,35

属性テーブル

 属性テーブルは、その直前のネームテーブルに対するパレットデータです。しかし総タイル数が960なのに、属性テーブルの領域は64バイトしかありません。 これは、2x2の4つのキャラのグループ毎にパレットを1バイトで指定していて、それが8x8=合計64になるからです。BGは32x30ですから縦は余りますね。 そしてその1バイトのパレット指定データはどうなっているかというと、ビット0~1が左上のグループのパレット番号の上位2ビット、 ビット2~3が右上、ビット4~5が左下、ビット6~7が右下となっています。

 ここで注意することは、指定できるのは2進数の上位2ビットという点です。0〜15までのBGのパレットのうち、 パレット0〜3を使うならば0(%0000)の00、パレット4〜7なら4(%0100)の01、パレット8〜11なら8(%1000)の10、パレット12〜15なら12の(%1100)の11を指定することになります。 つまりパレットは連番で16/4=4種類うちのいずれかを使用します。

 以下の図は例です。属性テーブルのパレット指定は2x2のセットで左上・右上・左下・右下の順なのに、 ネームテーブルのキャラのアドレス指定は1つずつ左上から右下に横方向に敷き詰められています。、この並び方の違いのせいでパレット指定はわりと面倒です。

 なお、パレットの0〜15のうちの0・4・8・12は透明(BG抜き)になり、どんな色を指定しても反映されないので、 実質的に使える色は減ってしまいます。画面のフェードイン・フェードアウトなどをやる場合は、パレットを上手く書き換えるテクニックが必要ですね。

 ちなみにこの制約はスプライトのパレット指定についても同様で、第5章で説明したスプライト情報の4つのうちの3バイト目の、ビット0~1で指定するのもBGと同じやり方で指定します。

 以下のコードは例です。eorという命令がありますが、これはXOR演算を行う命令で、0→1→0→1と値を交互に変えたいような場合に便利です。 この例は、BGのパレットをしましま模様にします。


	; $23C0の属性テーブルにロードする
	lda #$23
	sta $2006
	lda #$C0
	sta $2006

	ldx #$00    ; Xレジスタクリア
	lda #%00000000				; 4つともパレット0番
	; 0番か1番にする
loadAttrib
	eor #%01010101				; XOR演算で一つおきのビットを交互に0か1にする
	sta $2007				; $2007に属性の値($0か$55)を読み込む
	; 64回(全キャラクター分)ループする
	inx
	cpx #64
	bne loadAttrib

スクロール

 そしていよいよBGのスクロール機能の説明です。とりあえず1/60秒毎に1ドット分スクロールさせるのはとても簡単です。以下のようにするだけです。

	; BGスクロール(Scroll_X,Scroll_Yという変数があるとして)
	lda $2002			; スクロール値クリア
	lda Scroll_X	; Xのスクロール値をロード
	sta $2005			; X方向スクロール
	lda Scroll_Y	; Yのスクロール値をロード
	sta $2005			; Y方向スクロール

	inc Scroll_X	; スクロールX値を加算
	inc Scroll_Y	; スクロールY値を加算

 スクロールはこれだけで出来ます。ただし、これでは同じ画面がループするだけです。 普通のゲームではスクロールするたびに新しい背景が出なくてはならないので、画面外をこっそり更新する必要があります。 それにはネームテーブルを画面外でうまく書き換えなければなりません。そのやり方は後の章で説明します。

BG横スクロールプログラム

 とりあえず、星が流れるサンプルを作ってみました。これをダウンロードして、nesasm giko011.asmしてください。

 相変わらず左上に2番以降のスプライトの下部が出てますが、これは座標を画面外にするか、属性をBGの後ろにするか、0番スプライトを透明にすれば消えます。気になる人はやってみてください。

 こういう画面のゲームの場合、星をスプライトにして、敵をBGに描いて敵を大量に出しているものもあるようです。逆転の発想ですね。


トップページ 前のページ 次のページ
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送