スプライトを表示する
WRAMにOAMの写しを置き、毎フレームDMAで転送してスプライトを表示します。
OAMの写しを使う
OAMにはVブランク中しか書き込めませんが、スプライトの位置はメインの処理の中で何度も書き換えたくなります。そこで、OAMと同じ形式の544バイトの領域(OAMの写し)をWRAMに用意し、メインの処理ではそちらを書き換えます。NMI処理ルーチンは、毎フレームその内容をDMAでまとめてOAMへ転送します。
ここでは、WRAMの$0200~$041FをOAMの写しにします。OAMの形式はスプライトを参照してください。
| WRAMのアドレス | 内容 |
|---|---|
| $0200~$03FF | 下位テーブル(1スプライト4バイト × 128) |
| $0400~$041F | 上位テーブル(1スプライト2ビット × 128) |
OAMの写しを初期化する
使わないスプライトは画面外に置いておきます。OAMを0で埋めると、128個のスプライトがすべて画面の左上に表示されてしまいます。
InitOamBuffer:
REP #$30
LDX.w #$0000
LDA.w #$E000 ; X座標 = $00、Y座標 = $E0(画面の下の外)
.loop
STA $0200,X ; X座標・Y座標
STZ $0202,X ; タイル番号・属性 = 0
INX
INX
INX
INX
CPX.w #$0200
BNE .loop
LDX.w #$001E
.loop2
STZ $0400,X ; 上位テーブル: X座標の最上位ビット = 0、小さいほうの大きさ
DEX
DEX
BPL .loop2
SEP #$20
RTS
Y座標が$E0のスプライトは225ライン目から描かれるので、224ラインの表示では見えません。ただし、高さが32ピクセルを超えるスプライトは、はみ出した部分が画面の上端に回り込んで見えてしまいます。64×64のスプライトを使う場合は、Y座標を$F0などにするか、別の方法で隠してください。
スプライトの設定
; タイルデータの置き場所と大きさ
LDA.b #$03
STA $2101 ; OBJSEL: 8×8と16×16、タイルは VRAM $6000
LDA.b #$11
STA $212C ; TM: BG1とスプライトを表示する
; スプライト0を(112, 96)に表示する
LDA.b #$70
STA $0200 ; X座標
LDA.b #$60
STA $0201 ; Y座標
STZ $0202 ; タイル番号 0
LDA.b #$30
STA $0203 ; 属性: 優先度3、パレット0、反転なし
OBJSELのビット2-0は、タイルデータの置き場所を$2000ワード単位で指定します。3なら$6000です。この設定では、属性のビット0(第2テーブル)を使うタイルは$7000~$7FFFから読まれるので、BGを表示するの例のタイルマップ($7800~)と重なります。第2テーブルを使う場合は配置を見直してください。スプライトのタイルデータとパレット(色番号128~255)は、BGと同じように強制ブランク中に転送しておきます。
![]()
(112, 96)に8×8のスプライトが1つ表示されています。画面写真は、サンプルの画面にこのページのコードを実行し、エミュレーターで撮ったものです。
毎フレームOAMへ転送する
NMI処理ルーチンの中で、OAMの写しをDMAでOAMへ転送します。
; NMI処理ルーチンの中で(Aは8ビット、X・Yは16ビット)
STZ $2102
STZ $2103 ; OAMADD: OAMの先頭から書き込む
STZ $4300 ; DMAP0: A→B、アドレス増加、モード0
LDA.b #$04
STA $4301 ; BBAD0: OAMDATA($2104)
LDX.w #$0200
STX $4302 ; A1T0: OAMの写しの先頭
STZ $4304 ; A1B0: バンク$00(WRAM $7E:0200 の写し)
LDX.w #$0220
STX $4305 ; DAS0: 544バイト
LDA.b #$01
STA $420B ; MDMAEN
スプライトを動かす
メインの処理では、OAMの写しの座標を書き換えるだけです。
; スプライト0を右へ1ピクセル動かす
LDA $0200
INC A
STA $0200
BNE .done
LDA $0400
EOR.b #$01 ; X座標が256を越えたら最上位ビットを反転する
STA $0400
.done
X座標は9ビットなので、画面の左右の端をまたいで動かす場合は、上位テーブルのX座標の最上位ビットも書き換える必要があります。