スプライトを表示する

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と同じように強制ブランク中に転送しておきます。

BG1とスプライトを1つ表示した画面

(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座標の最上位ビットも書き換える必要があります。

参照

スプライト
OBJSEL レジスタ
OAMADD レジスタ
OAMDATA レジスタ
NMIとフレームの処理