MSXのスプライトを学ぶ
今回はスプライトに関する記事です。スプライトはGRAPHIC1、GRAPHIC2の両モードで使用可能です。かなりクセが強い機能になっています。
まずはスプライトについて学習してみましょう。
スプライトの仕組み
スプライトは面という概念になっています。背景画像(パターンネームテーブル)の上にそれらの面が表示される。というような仕組みです。
面にはスプライト番号という番号が付きます。スプライト番号には優先順位がつけられていて番号が小さいほうが優先度が高くなります。
スプライトが横に並ぶと優先度の低いスプライト(スプライト番号の大きいほう)が表示されなくなる仕様になっています。
スプライトは8x8ドットのスプライトモードと、16x16ドットのスプライトモードの2つがあります。16x16ドットのほうがドット数が多いので表現力が高くなります。当記事では16x16ドットのスプライドモードしか使いません。
スプライトの形状はスプライトパターンテーブルと呼ばれるVRAM上にあります。8x8でひとつのパターンになります。16x16のスプライトモードの場合、4パターンでひとつのスプライトを構成します。
スプライトを表示するために必要なVRAM
また、VRAM?と思われるかたもいらっしゃるかと思いますが、MSXで何かを表示するためにはVDPとVRAMは必須です。VDPとVRAMを極めてこそなんぼ。それがMSXなのです。
さて、スプライトを表示するために必要なVRAMの構造は以下のとおりです。
スプライトパターンテーブル
スプライトの形状(パターン)を定義するVRAMアドレスです。パターンの定義のやりかたはPCGと同じです。前回の記事で文字を自由に書き換えるためにドット絵を1ライン(8ドットずつ)定義したあのやり方と同じです。
スプライトパターンテーブルは16x16ドットスプライトの場合、形状を最大64個まで作成できます。
注意してほしいのはパターンにはパターン番号というものがついてます。3800H(#0)から始まり8バイトごとにパターン番号がひとつずつ増えていきます。パターン番号とスプライト番号は異なります。
スプライト番号はスプライトアトリビュートテーブルの4バイトごとに付きます。
スプライトアトリビュートテーブル
スプライトアトリビュートテーブルというVRAMアドレスに対して値をセットすればスプライトが表示されます。スプライトアトリビュートテーブルは4バイトごとに値をセットします。
+0 : Y座標(0-191)
+1 : X座標(0-255)
+2 : パターン番号
+3 : カラーコード
16x16ドットのスプライトモードの場合、パターン番号がちょっと特殊です。16x16ドットのスプライトを作るためには4つのパターンを組み合わせて1つのスプライトになります。その4つのパターン番号のどれかひとつをセットするとそのパターン番号が組み合わせになっているスプライトが表示される仕組みです。筆者はめんどくさいので、#0、#4、#8、#12、、といったかたちで4個とびでセットするようにしています。カラーコードを0にすると透明になります。透明だと後述する衝突判定では判定対象となりません。
スプライトの衝突判定
異なるスプライト番号間で色が付いている箇所どうしが重なると衝突判定が行われます。透明なスプライトは衝突判定の対象にはなりません。
と、、、衝突判定されるのはわかるのですが筆者はこのステータスレジスタを使ったことがありません。なぜなら「どのスプライトと、どのスプライトが衝突したのか?」というのは結局、スプライトの座標どうしを計算しないとわからないためです。だったら、衝突判定フラグなんてなくていいじゃん。と思っているのです・・。
スプライトの用途
スプライトをどんな場面で使うのか?という点です。
スプライトはその特性上、平行に5個以上ならぶと5個以降の重なってるところが消えてしまいます。なので大量にキャラクターを表示する用途には向いていません。また、例えば4色使うスプライトキャラを1体表示させようとすると4枚のスプライト番号を重ねて表示させる必要があります。これだけで、次のスプライトを平行に並ばせようものならそのスプライトが消えてしまいます。
なので、筆者は以下のように使うようにしています。
・スプライトは最低限、自キャラのみとする
・PCGキャラ(文字の形状を変えたキャラ)にちょっとずらす形で表示する場合にはスプライトを使う
・敵キャラや自キャラ等から発射される弾などはスプライトにする
・一瞬だけ動くようなキャラはスプライトにする。例えばゼルダで何かアイテムを見つけたときにキャラの頭上に表示されるびっくりマークなど。
つまり、スプライトは多用しない。できるだけ動くキャラもPCGで動かす。そういう使いかたです。
(特に縦型の)シューティングゲームではスプライトを多用するみたいです。
ファルコムのドラスレファミリーや、ヴァリスなんかはスプライトを使いまくってますけどスプライトが横にしょっちゅう並ぶのでチラつきまくりです。横に並んだらスプライトアトリビュートをいじくって優先順位を変えてできるだけチラつきを抑える。というテクニックもあるようですが筆者は其のテクニックをよく知りません。。。
マシン語でスプライトを表示させてみる
今回までの記事でGitHubがゴミ屋敷みたいになってしまったので、今回からサンプルコードごとにディレクトリを分けるようにしてみました。まずはサンプルコードをダウンロードしてみてください。
解説
今回のソースコードではsprite.asmとdata_sprite.asmを追加しています。
https://github.com/sailorman-msx/games/tree/main/src/sample006
sprite.asmはスプライトパターンの作成(CreateSpritePattern)と、スプライトアトリビュートテーブルの作成(PutSprite)を行う2つのサブルーチンを用意しています。data_sprite.asmはスプライトパターンのパターン(形状)のデータです。
initialize.asmにはスプライトを表示させるためのX座標とY座標を格納する変数を定義していて、実際にスプライトアトリビュートテーブルに格納するときにはその変数の値を8倍して座標変換して表示させています。(PutSpriteを参照してください)
それ以外で今回、特筆するような新しい学習要素はありません。
initialize.asm 抜粋
; スプライト座標格納用
WK_PLAYERPOSX:equ $D003 ; 1バイト(0-31)
WK_PLAYERPOSY:equ $D004 ; 1バイト(0-23)
z80asm -b sample006.asm でアセンブルして、実行するとこんな画面が表示されますよ。今回のスプライトは16x16のスプライトを2枚重ねて画面の中央あたりにキャラクターを表示させています。
次回はカーソルキーでスプライトを動かしてみようと思っています。
動くと楽しくなってきますよ!
では、また!!