TOP > プログラミング関係解説&調査 > スプライトについて

スプライトについて

当ページの内容は、ある程度のプログラミングの知識を必要とする。
まず、プログラミング関係解説&調査をひととおり読んでいただきたい。

スーパーファミコンにおけるグラフィックは、背景(BG)とキャラのドット絵(スプライト)に分かれる。
背景はそのまま、マップの画像であり、透過部分も設定可能。セリフ表示のウィンドウなどは一番上に表示させるなど、最大4枚まで重ねることができる。
その背景の上に載せて動かすことができる小さめサイズの画像がスプライトである。
RPGであればキャラクターのドット絵に使われることでおなじみである。
他には、マップ背景であっても扉など小さめで動かす画像もスプライトを利用している。
戦闘ならダメージ量を表示する数字や技エフェクト、コマンドカーソルなどもスプライトである。

ここでは、キャラのドット絵(スプライト)の仕様を大まかに説明する。
筆者は専門家でも何でもないので、説明に間違いが含まれているかもしれないし、用語の使い方もおかしいかもしれないが、ご了承いただきたい。
ネットを探しても、ある程度噛み砕いた説明はほとんど英語で、日本語での説明はあまりなく(あるかもしれないが筆者は見つけられなかった)、ここでは「ライブ・ア・ライブ」を元にして、スーパーファミコンの仕様を説明してみる。

スーパーファミコンの仕様では、背景を最大4枚、スプライトを最大128体設置できる。
これら画像データは、

  1. ゲームのカセット
  2. スーパーファミコンのメモリWRAM(通さない場合あり)
  3. グラフィックデータ用のメモリ
    VRAM, CGRAM, OAM
  4. 画像処理用チップ(CPU)
    PPU(Picture Processing Unit)
  5. テレビ画面

というような順序で処理をしている、らしい。

グラフィックデータ用のメモリが3種類もあるが、

  • VRAM: Video RAM
    グラフィックデータ(画像の構造)を記録するメモリ。
    $10000(65,536)バイト = 64キロバイト。
    アドレスをbyteではなくwordで指定するため注意が必要2byte(バイト)で1word(ワード)になる。
  • CGRAM: Color Generator RAM
    スプライトや背景の色情報(カラーパレット)を記録するメモリ。カラーパレット16色(32バイト)を1単位として16テーブルを格納できる。
    $200(512)バイト。
    グラフィック用CPUである、S-PPU2の中にあるメモリ領域(らしい)。
    アドレスをbyteではなくwordで指定するため注意が必要2byte(バイト)で1word(ワード)になる。
  • OAM: Object Attribute Memory
    スプライトの配置・色などの情報を記録するメモリ。
    そういった配置・色の情報を、Object Attribute(オブジェクト属性)という。
    $220(544)バイト。
    グラフィック用CPUである、S-PPU1の中にあるメモリ領域(らしい)。

となっている。
上の3種類のメモリは、本体のメモリ領域にアドレスが割り振られておらず、I/Oポート用のアドレスを通さないとデータのやりとりができない。
グラフィックのデータは量が多い上、1フレーム1回更新していかなければならないので、スーパーファミコンのCPUを通さずにデータの読み書きをする、DMA(Direct Memory Access)転送という高速の転送方法を使うのが一般的(らしい)。
詳細はこの先で説明していく。
サブルーチンは次ページで紹介しているが、まずはこのページの説明からお読みいただきたい。

スプライトのデータの基本

ライブ・ア・ライブの話に戻すと、ライブ・ア・ライブにおいては、フィールド(マップ)上では、キャラクターのスプライトのサイズは16×16ピクセルである。
戦闘では32×32ピクセルであり、別々のグラフィックが用意されていることは見るだけでもわかる。
どちらのサイズにしても、データは8×8ピクセルを1つの単位として、16×16ピクセルのキャラなら8×8ピクセルを4個、32×32ピクセルのキャラなら8×8ピクセルを16個並べてドット絵キャラが作られている。

スプライトは1つの画面に128個まで載せることができる。
解説サイトなどではOBJ0~OBJ127とナンバリングされている。
スプライトの重ね順はナンバーが小さいほど手前(上)に被さるため、例えば戦闘でダメージ量を表示する時は、キャラのスプライトより、数値のスプライトの方が小さいナンバリングになる。
マップの扉にスプライトを使うのなら、キャラが扉を開いて扉の向こうへ移動後に扉を閉じる、という一連の動作の時、スプライトのナンバリングを変えることでキャラを手前に置いたり、扉を手前に置いたりして、扉の奥へ移動、または手前に移動したことが表現できる、ということである。

ここでは基本として、キャラのスプライトで説明をしていく。

例を見た方がわかりやすいので、ここでは、フィールドにおけるサンダウンの正面向きのスプライトがどういう構造かを説明していく。
16×16ピクセルのドット絵は以下のようなデータで作られている。

いわゆるエクセル方眼紙形式だが、1マス分が1×1ピクセルに対応していると見ていただきたい。
8×8ピクセル単位で赤線で区切っているが、これが8×8ピクセルを4個つかって描いた16×16ピクセルのキャラである。
画像は8×8ピクセルを1単位として読み込み・書き出しをするため、8×8ピクセルサイズの画像をタイル1個、というような数え方をするようである。

各マスに番号が書かれているが、これが色情報に対応した値である。
0に指定されているのは白色ではなく、透過部分であり、背景の上にキャラを設置すると、0の部分は透過して背景が表示される。1以上が色に対応。

スーパーファミコンのスプライトの色だが、色自体は32,768色から選択できる。
(後で説明するが、色はBGR555フォーマットという形式を使っている)
ただし、1つのスプライトの中では、予め決めておいた16色、つまり1バイト($0~$F)分から各ピクセルの色を決めて割り振る。
「予め決めておいた16色」のことをカラーパレットといい、サンダウンでいえば、カラーパレットの$0に透過色、$1に黒……というように色と値を割り振ってある。
上画像を見るとわかるが、サンダウンの正面向きのスプライトだと、実際に使っている色は透過部分込みでも10色である。
16×16ピクセルの各ピクセルに4ビット($0~$F)の値を割り振るのだから、2ピクセルを1バイトとして、キャラのドット部分と色を記録すればいいのでは?
つまり左上から順に、00 00 01 11, 次の行は00 00 18 77, 00 11 18 88……としたら赤い8×8ピクセル領域は32バイトのデータになるのではないか。

……と思いきや、実はスプライトのデータの記録方法はそうではない。
人間の感覚とは少々ずれているというか、ややこしい。

8×8ピクセルを1つの単位として、スプライトのデータが記録されている、と述べたが、その8×8ピクセル分のデータが以下の通り。
以下がサンダウンの左上部分8×8ピクセル領域のデータになる。

07 00 0B 03 38 00 73 30 2F 0F 1F 00 27 00 3D 09
00 00 03 04 00 07 30 0F 0F 10 00 00 00 18 0A 00

32バイト分のデータになるが、サンダウンの画像と比較して、どこの数値とも一致していないことがわかる。
では、どうやって上の図のような数値になるのか?

先に、16×16ピクセルの各ピクセルに4ビット($0~$F)の値を割り振る、と記した。
1ピクセルにつき、4ビットのデータが必要になるので、ドット絵を4枚に分けて、1枚ずつに1~4ビット目の値を記して重ねてデータにしよう。
というのが、スーパーファミコンにおけるスプライトのデータ記述方法なのである。
このようにビット毎に分けてデータを記す方法を「ビットプレーン」という。

ビットプレーン - Wikipedia

実例を出した方がわかりやすいので、サンダウンのスプライトで説明する。

サンダウンの左上8×8ピクセル部分を取り出し、さらに横1列ずつ(4バイト分)に分けてみよう。
1ピクセルにつき4ビットのデータがあるから、例えば一番上の列「00000111」は、

数値00000111
2進数4ビット00000000000000000000000100010001

2進数4ビットの各桁を、上から順にbit3, bit2, bit1, bit0とすると、各桁だけ集めて、

bit
bit3%0000 0000 = $00
bit2%0000 0000 = $00
bit1%0000 0000 = $00
bit0%0000 0111 = $07

これを、

bit0 bit1
bit2 bit3

と並べると

07 00
00 00

となるが、これが、サンダウンの左上部分8×8ピクセル領域のデータの

07 00 0B 03 38 00 73 30 2F 0F 1F 00 27 00 3D 09
00 00 03 04 00 07 30 0F 0F 10 00 00 00 18 0A 00

左隅の2×2部分に合致している。
初めてだとまったくもってわかりにくいこの方法で、スプライトのデータを記述しているのである。

2列目以降も同じ処理をするのだが、図解すると以下のような感じである。

2列目は以下のように考える。

数値00001877
2進数4ビット00000000000000000001100001110111

bit
bit3%0000 1000 = $04
bit2%0000 0011 = $03
bit1%0000 0011 = $03
bit0%0000 1011 = $0B

となり、次の2バイト部分に対応している。

07 00 0B 03 38 00 73 30 2F 0F 1F 00 27 00 3D 09
00 00 03 04 00 07 30 0F 0F 10 00 00 00 18 0A 00

……という手順でスプライト画像からデータができるが、逆にデータから画像へ変換する場合はデータを区切りながら逆算して……と、何にせよ手で計算するのは面倒なので、やっつけではあるがJavaScriptで出力できるようにしてみた
JavaScriptをブラウザで実行してコンソール出力できるPlayground | MDNなどで試してみていただきたい。

さて、ここまでが「サンダウンのドット絵を4分割した左上部分」の話である。
この作業を残り3ヶ所繰り返して、分割されたデータをくっつけると、サンダウンの16×16ピクセルのドット絵が完成、ということになる。
16×16ピクセルで$80(128)バイトの容量を使っていることがわかる。
実際のデータは以下の通りなので、興味があれば試してみていただきたい。

左上
07000B03380073302F0F1F0027003D09
000003040007300F0F10000000180A00

右上
E000D0C01C00CE0CF4F0F800E400BC90
0000C02000E00CF0F008000000185000

左下
2F013F1E5E215E1D7F387D207F060F00
01101E003D3D1D213800200206060000

右下
F480FC787C807A98FE0C1E045E4434E0
80087800B8B898840C0004E044A0E0E0

さて、この正面向きサンダウンのデータは、ROM上では$CF:074B$CF:07CAに格納されている。
ただ、上の数値そのままではない。
左上と右上は数値が少し異なる。
スプライトのデータを呼び出すサブルーチンが$CE/D47E$CE/D89Dで、$7E:8000~にスプライトのデータを順にコピーしていくのだが、特定条件の時に値を計算し直している。
というのは、キャラが正面向きの場合、どちらかの足を上げたポーズで作られている。
そのスプライトを左右判定させて、正面向きの歩行のモーションを作っている。
(後ろ向きの場合も同じ理屈)
ゲームのROMには、片足をあげた状態のポーズのデータしか入っていないのだが、VRAMにデータを送る時、ROMのデータそのままと、左右反転させたパターンの両方を転送する。
サンダウンの場合、正面向きスプライトを左右反転させても、上半身のドットに変化はないが(左右対称)、下半身は左右反転すると下4ドット部分は別グラフィックである。
そういった計算を$CE/D47E$CE/D89Dで行う都合で、ROMのデータそのままがコピーされるのではない、ということになる。
その計算し直した$7E:8000~を、VRAMに送り、スプライトに変換している。
サンダウンのように左右対称部分が多いキャラはROMに入っているデータの大半がVRAMにコピーされることになるが、おぼろ丸のように髪型から左右非対称のキャラなどはROMに入っているデータとは別物のデータがVRAMに入ることもある。

ここでVRAMについてざっと説明する。
VRAMの容量は64KB、グラフィックデータを置けるのはメモリアドレス$0000$FFFFの領域ということになる。
$0000$BFFFがBG(背景)用、$C000$FFFFがスプライト用である。

VRAMに送るデータは、キャラ1人分のスプライトだけではない。
例えば西部編なら、西部編を開始した時点で、VRAMのスプライトの領域にサンダウン、マッドドッグ、サクセズタウンの人々、馬など、$C000$FFFFに一斉に設置される。
4×4ピクセル(32バイト=$20バイト)の画像を単位として(一般的な名称として「タイル」にする)、16個($10個)のタイルを横に並べると、タイル16個で$200バイト分になるが、これを横1列としてVRAMにスプライトを並べていく。
ただ、4個のタイルで1つのキャラのスプライトを作る都合で、あたかも、キャラの上半身部分だけ横に8人分並べてから、次の行にキャラの下半身部分を8人分並べる、といったデータ構成になる。
タイル1個を■とすると下のような感じである。

■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■

4×4のデータが4つ集まった、

■■
■■

が、16×16ピクセルのキャラ1人分のデータである。
2行に分けられているので、

スプライトの部分VRAMのアドレス
左上$C000$C01F
右上$C020$C03F
左下$C200$C21F
右下$C220$C23F

に、書き込まれるようになっている。

つまり先に示したサンダウンのデータは、VRAM上だと、

左上 $C000$C01F
07000B03380073302F0F1F0027003D09
000003040007300F0F10000000180A00

右上 $C020$C03F
E000D0C01C00CE0CF4F0F800E400BC90
0000C02000E00CF0F008000000185000

左下 $C200$C21F
2F013F1E5E215E1D7F387D207F060F00
01101E003D3D1D213800200206060000

右下 $C220$C23F
F480FC787C807A98FE0C1E045E4434E0
80087800B8B898840C0004E044A0E0E0

に入っているデータなのである。
VRAMからスプライトを読み取るなら上の点に注意しなければならない。

色のデータとCGRAM

これまでのデータから、サンダウンの16×16ピクセルのスプライトのデータとして、

00000111 11100000
00001877 77810000
00111888 88811100
01778899 99887710
00187777 77778100
00011111 11111000
00188111 11188100
00117143 34171100
00181117 71118100
00177771 17777100
01EDDD1E E1DDD100
0187771E E1177810
01777111 11117710
01711181 88811710
01111FF1 87811710
00001111 EEF10100

という32バイトのデータができた。
ただ、これだけでは、数値に対応した色がどれなのかがわからない。

ここで、スーパーファミコンで扱える、32,768色の色について説明する。
スーパーファミコンにおける色データは、BGR555フォーマットという形式を使用している。

BGRのBは「Blue」、Gは「Green」、Rは「Red」であり、青・緑・赤の3色をどれだけ混ぜるかという度合いで色を作る。
「BGR」ではなく「RGB」なら聞いたことがある、という方もいらっしゃるかもしれない。

RGB - Wikipedia

現代のコンピュータなどのデジタルデータにおいて、RGB24ビットカラーがだいたい標準である。
RGBは赤・緑・青という色の順番で、各色を$00$FF0~255)の度合いで混ぜ、色データを24ビットのデータとする。
純粋な「赤」だったら、赤・緑・青の順に、「$FF0000」だし、赤・緑が最大で青がない「$FFFF00」は黄色になる、といった感じである。

一方、上の説明にある「15ビットカラー」が、BGR555フォーマットの正体である。
色データに15ビット使う、つまり、青・緑・赤にそれぞれ5ビットずつ割り振るのである。
これなら、%0 00000 00000 00000 と16ビット=2バイトに色データが収まる(一番上のビットは使わず0とする)。
ただ、24ビットカラーだと、例えば赤に$00$FFの256段階色調が使えたが、15ビットカラーでは、$00$1Fの32段階色調に減ってしまう。
青が32通り×緑が32通り×赤が32通りで、32,768色が使えるということになるから、基本的には大半の色が使用可能と考えても問題はないのだが。
ただ、色調が減ったことで少々問題もありそうなので、この先の説明もお読みいただきたい。

さて、スプライトには最大で16色を割り振ることができる。ただしその中で1色は透過部分に使うので15色と考えて良い。
色を16色割り振ったデータを「カラーパレット」という。
各番号に対応した15ビットカラー2バイトの値から、スプライトの色が決まる。
カラーパレット1個につき、2バイト×16色だから、$20バイト(32バイト)が使われている。

ファミコン・スーパーファミコンあたりの時代のゲームに詳しい方なら、スプライトの構造はそのままで、カラーパレットだけ変更することで、種類の異なる色替えモンスターを表現したり、街のモブキャラの髪色や服の色などだけ変えていることを知っているかもしれない。
本作でも同じ手法が使われており、おぼろ丸とカラクリ丸はスプライトの構造は同じままで色だけ変えていたり、各シナリオのザコ敵が最終編で色を変更して別の敵として出現している。

現在のゲーム画面にあったカラーパレットのデータを格納するのが、CGRAM(Color Generator RAM)になる。
CGRAMは$200バイト(512バイト)の容量がある。
CGRAMには、背景用カラーパレットを8個、スプライト用カラーパレットを8個格納できるようになっている。
CGRAMの領域の、アドレス$0000$00FFが背景用カラーパレット割り当て領域で、$0100$01FFがスプライト用カラーパレット割り当て領域である。

注意しなければならないのは、CGRAMのアドレスの指定方法で、byte(バイト)ではなく「word(ワード)」であるということ。
ワード - Wikipedia
ややこしいが、2バイトで1色分のデータだから、1色分を1ワードと考える方式らしい。
(スーパーファミコンのCGRAMでは2byteを1wordとしているだけなので、他では異なる場合があるため注意)

フィールドにおける各シナリオの主人公キャラのカラーパレットは、シナリオIDから呼び出している(サブルーチンは$C0/9A09~、後で紹介する)。
フィールドにおけるサンダウンのカラーパレットは、$CF:FA80から$20バイト分である。

103E A514 FF7F 3F43 5D26 1033 0602 FA01
F200 7F03 7F01 495E 8445 B56E AD35 0821

2バイトずつで区切ると上のようになる。
サンダウンのポンチョ部分などメインカラーになる$07番目のデータにあたる「FA01」をRGB24ビットカラーに変換してみよう。
上位バイト・下位バイトの順に並べると、「01FA」である。

$01FA = %0 00000 01111 11010

下から5ビット毎に区切って、一番上の1ビットは無視、上から順にBGRの順だが、5ビットのデータの下に3ビットの000をつけて、8ビットデータとする。

B: %00000 000 = $00
G: %01111 000 = $78
R: %11010 000 = $D0

これをRGBの順に並べれば24ビットカラー表記である。

RGB: $D07800

RGBで「$D07800」は、■こんな色になる。
なのだが、これだけだと少々不具合がある。

24ビットカラーを基準とすると、RGBの各色の下3ビットを切り捨てて15ビットカラーとしている。
つまり、24ビットカラーの白「$FFFFFF」は、本来なら各色が「%11111111」というデータなのだが、下3ビット切り捨てで、

B: %11111 000 = $F8
G: %11111 000 = $F8
R: %11111 000 = $F8

$F8F8F8になってしまう。
$FFFFFF$F8F8F8ではそこそこ色が異なるので、ゲーム画面(当時ならブラウン管テレビ)ではさほどではなくても、現代のパソコン用ディスプレイや携帯電話(スマホ)などの画面で見比べると、違いがわかってしまうだろう。

背景色
$FFFFFF
背景色
$F8F8F8

これは15ビットカラーのデータを強引に24ビットカラーに計算し直したためであり、%11111000%11111111の間の値であるのに無視したから起こる。
このままだと、色がやや暗めに表現されることになってしまう。
この強引な数値切り捨てを補正する手段としてPalettes | Super Famicom Development Wikiでは

R補正 = R + R / 32
G補正 = G + G / 32
B補正 = B + B / 32

として変換する方法を提案している。切り捨てではなく、かといって四捨五入でもなく、間の値を割合でうまく取ろうという補正である。
同じ補正の話は、
SNES技術資料 - 色フォーマット
にもあるので一般的手法のようである。
これなら、

B: $F8 + $F8 / 32 = $FF
G: $F8 + $F8 / 32 = $FF
R: $F8 + $F8 / 32 = $FF

と、ほぼ元の色が再現できる、ということである。
ネットを探すと、BGR555からRGB24ビットカラー変換を行うウェブサイトなどでも同じような補正をしているようだった。
(結局、スーパーファミコン側でどう調整しているのかまでは、資料を見てもよくわからなかったが)

ということで、$20バイトのデータを入れたらRGBカラー16色に変換するJavaScriptもやっつけで書いてみた。ソースコードが雑なのはお許しいただきたい。
上の方法での補正も込みにしている。
計算結果は以下のようになった。

No.BGR15
ビットカラー
RGB24
ビットカラー
$0$103E$84847B 
$1$A514$292929 
$2$FF7F$FFFFFF(※白)
$3$3F43$FFCE84 
$4$5D26$EF944A 
$5$1033$84C663 
$6$0602$318400 
$7$FA01$D67B00 
$8$F200$943900 
$9$7F03$FFDE00 
$A$7F01$FF5A00 
$B$495E$4A94BD 
$C$8445$21638C 
$D$B56E$ADADDE 
$E$AD35$6B6B6B 
$F$0821$424242 

上の色に従って色を塗れば、サンダウンのスプライトが完成する。
No.$0にも色が入っているが、実際には透過部分に当たる。

かつてスーパーファミコンの出力先であったブラウン管テレビと、バーチャルコンソールなどWiiU出力やニンテンドー3DSの画面、そして現代のパソコン用ディスプレイなどで見た場合、それぞれで色味には差が感じられるのではないかと思われる。
おそらく開発当時は、ブラウン管テレビでちょうど良い感じに色味を調整したのだろう。

なお、同じキャラなら常に同じカラーパレットが使用されるのではない。
例えば幕末編なら、明かりがある室内と、外や明かりがない廊下などとではカラーパレットが変わる。
おぼろ丸やとらわれの男、カラクリ丸の色をよく見ると、明かりがある部屋では明るめの色合い、暗い場所ではやや薄暗い色味のカラーパレットが採用されている。
城外マップで暗めのカラーパレットが採用されているのは、おぼろ丸が夜に尾出城に潜入したことを示すためと思われるが、ややわかりにくい(リメイク版だと完全に夜になっている)。
おぼろ丸なら、明るめのカラーパレットは$CF:FAC0~、暗めのカラーパレットは$CF:FE80~に入っている。
ちなみにとらわれの男とカラクリ丸のフィールド上でのカラーパレットは共通で、明るめは$CF:FA80~、暗めは$CF:FE40~である。つまり実はサンダウンとも共通のカラーパレットなのである。

スプライトのデータを呼び出すサブルーチンが$CE/D47E$CE/D89Dで、$7E:8000~に一気に$200バイト(512バイト)分のデータをコピーしている。
サンダウンなら$CF:074B$CF:0905にあたる。
16×16ピクセルで$80(128)バイトだから、$200バイトなら16×16ピクセルサイズを4個分ということになる。
(戦闘中の32×32サイズなら1個分である)
先の計算と同じようにして、データをマス目に並べて色を塗ってみると下のようになった。

順に、サンダウン正面向き、後ろ向き、横向きの歩行アニメーション用2パターンということになる。
これらのスプライトを左右反転させれば、正面向きや後ろ向きなら歩行アニメーションになるし、横向きは右向きにも左向きにもできる。
この4種がキャラの基本のスプライト4パターンということになる。
サンダウンの場合、後はイベント用のドット絵パターンがいくつかあり(クリスタルバーの扉を開ける時や、クレイジーバンチ銃撃時、最終編の銃を向けるドット絵など)、これらでフィールド(マップ)用のサンダウンのスプライトが揃う。

OAMについて

さて、VRAMとCGRAMの説明はしたが、最後にスプライトの配置などを記録するメモリOAM(Object Attribute Memory)についてざっくりと説明する。
OAMに記録されるデータはオブジェクト属性(Object Attribute)と呼ばれ、スプライトの座標、どのカラーパレットを使うか、スプライトの反転といった情報をまとめたものである。

OAMは$220バイトで、アドレス$0000$01FFと、$0200$021Fの領域に分かれている。
スプライト1つ分のオブジェクト属性データは、$0000$01FFに4バイト、$0200$021Fに2ビットで記録される。
2ヶ所に分かれるので、最初の$0000$01FFを下位テーブル(Primary (low) table)、$0200$021Fを上位テーブル(Secondary (high) table)と記述し説明しているウェブサイトが多く、ここでも採用させていただく。
スプライトは最大で128個設置可能。

キャラが動けばオブジェクト属性の座標は上書きされて新しくなっていく。
ボタン判定にも記したが、スーパーファミコンの画面1枚分を描画する処理の間の空白時間VBlank(1フレームに1回入る)で、VRAMはじめ、CGRAMやOAMのデータを更新している。

下位テーブル($0000$01FF)のデータ

4バイトのデータは以下のように割り振られている。

  • 1バイト目:
    キャラ表示位置 ピクセル単位の水平位置(X座標)
    ※上位テーブルのbit0を一番上のビットに設置
  • 2バイト目:
    キャラ表示位置 ピクセル単位の垂直位置(Y座標)
  • 3バイト目:
    CHAR / VRAMの中のスプライトのアドレス
    ※4バイト目のbit0を上につけて9ビットでアドレスとする
  • 4バイト目:
    • bit1-3:PAL / カラーパレットNo.の値(3ビット、0~7がそれぞれ、カラーパレットNo.8~Fに対応)
    • bit4-5:PRI / 背景に対する優先度(下参照)
    • bit6:FLIP / スプライトをX軸反転するなら1
    • bit7:FLIP / スプライトをY軸反転するなら1

1バイト目の、ピクセル単位の水平位置(X座標)だが、スーパーファミコンの画面サイズが横256×縦224ピクセルのため、X方向にキャラを少しはみ出した状態にしたい時など、X座標が$FFを越えることがあるため、上位テーブルに$FF以上の値がはみ出した時のための1ビットの値が確保してある。つまり9ビット表示である。
ちなみに座標は負の値を設定でき、その場合はキャラを画面隅に一部だけ表示させたり、一時的に非表示にする、といったことが可能。

bit4-5の背景に対する優先度だが、2ビット(つまり0~3)で、背景とスプライトの重ね順を表す。
基本は値が大きいほど、スプライトが手前側、つまり重ねた時に上に設置されることになる。
背景にも1枚ずつ優先度が設定されているので、そちらと合わせて実際の重ね順を判定することになるのだが、ここでは詳細は省く。
snes-docs-ja/video/obj/priority.md 優先度
などを参照のこと。

なお、CHAR、PAL、PRI、FLIPといった省略表記は、海外の解説サイトなどで使われているので、参照のため併記した。

上位テーブル($0200$021F)のデータ

  • bit0:X座標(上位1bit)
  • bit1:サイズ (0=小, 1=大)

bit0は上で説明した通り、X座標の一番上のビットになる。

bit1はスプライトのサイズを表すのだが、この値と、$00:2101経由でVRAMに送られる命令によって実際のサイズが決まる。
snes-docs-ja/video/obj/obsel.md 2101h - OBSEL - オブジェクトサイズ/ベースアドレス (W)

bit1が0ならサイズ小、1ならサイズ大の指定だが、$00:2101のbit5~7に入る4ビットの値で、実際のピクセル数が以下のように決まっている。

bit5~7サイズ小サイズ大
$08×816×16
$18×832×32
$28×864×64
$316×1632×32
$416×1664×64
$532×3264×64
$616×3232×64
$716×3232×32

実際の例を示す。
さきほどのサンダウンのスプライトのオブジェクト属性が、上位テーブルの2バイトは「$785D0024」、下位テーブルの2ビットは「%00」とする。

  • X座標:$78(120)
    ※下位テーブルbit0は0なので$78 = %0111 1000の頭に0をつける、つまり$78そのままで問題ない
  • Y座標:$5D(93)
  • VRAMの中スプライトのアドレス位置:$00
    (一番最初の位置のスプライトにあたる)
  • カラーパレットNo.:%010(カラーパレットNo.A)
  • 背景に対する優先度:%10(優先度は2)
  • スプライトをX軸反転:%0(反転しない)
  • スプライトをY軸反転:%0(反転しない)
  • スプライトサイズ:%0(小)

というようになる。
座標やスプライトの反転などはキャラの動きにより1フレーム毎に刻々と変化していくことになる。
サンダウンが左を向いたなら、VRAMの中のスプライトの呼び出しアドレスを変えて、サンダウンが左向きのスプライトをロードして表示する、といったことも内部で処理し続けているのである。

戦闘・メニュー画面におけるスプライト

マップでは16×16サイズだったキャラのスプライトであるが、戦闘では32×32ピクセルの別のスプライトを使っている。
メニュー画面でも戦闘と同じサイズのキャラのスプライトを使っている。
先に述べたとおり、32×32ピクセルサイズだと、容量は$200(512)バイトになる。

敵はサイズが様々だが、画像データをVRAMにロードした後、背景として設置している。
味方の場合はフィールドと同じくスプライト扱いである。
ちなみに、ダメージを受けた時に表示される数字、攻撃範囲を表示するカッコのような表示もスプライトとして表示するが、キャラの上に被せる形になる。

ここでは、味方キャラのスプライトについてざっと紹介する。
味方キャラのスプライトはVRAMのアドレス$4000以降に設置される。
戦闘では1つの向きのアニメーション2パターンだけが、アドレス$4000に設置され、向き変えをする度に更新される。
といっても、右上向きのスプライトを左右反転で左上向きになるし、右下向きのスプライトを左右反転で左下向きになる。
さらに、技のモーションや、ダメージをくらった時、戦闘不能時などのスプライトもあるから、1キャラあたりのパターン数はけっこうある。

ただ、戦闘中は、スプライトの左右反転をオブジェクト属性で制御しており、VRAMに読み込まれるスプライトは必ず右向き固定である。
VRAMに読み込まれるデータはそのまま、ゲームのROMに入っており、フィールドのスプライトのように左右反転で別途計算されてはいない。

1つのスプライトで、8×8マスサイズのタイルが4×4=16個必要になるので、最初の32×32ピクセルサイズのキャラは、

$4000~401F$4020~403F$4040~405F$4060~407F
$4200~421F$4220~423F$4240~425F$4260~427F
$4400~441F$4420~443F$4440~445F$4460~447F
$4600~461F$4620~463F$4640~465F$4660~467F

と、散らばった位置に設置される。
値の変換やカラーパレットなどの処理はフィールド時と変わらない。

試しに、アキラの戦闘中のスプライトを変換・色を塗ってみた。

スプライトのデータは、$D9:FC20
カラーパレットは、$D6:22A0
(カラーパレットのデータは、同一キャラでも、フィールドと戦闘では別に設定されている)

実は通常の待機時、右隅の8ピクセル分は透過になっている。モーションによっては横いっぱいまで使うこともある。
このため、スプライトのデータ$D9:FC20~は、右隅の横8×縦32ピクセル分のデータはなく、横24×縦32ピクセル分、$180(384)バイトとなっている。容量の節約のためであろう。
VRAMにコピーする時に横の横8×縦32ピクセル分の透過部分を加えている。

おぼろ丸とカラクリ丸はスプライトのデータはまったく同じで、カラーパレットが異なるだけなので、おぼろ丸はカラーパレット$D6:2240~、カラクリ丸はカラーパレット$D6:2340~で色を塗ると、以下のように各キャラが完成する。
透過部分以外の15色の中で一致するのは4色だけで、ぱっと見ただけだと同じような色に見える襟巻きや足袋部分だが実際には色は異なる。

次ページでは、サブルーチンを紹介する。



このページをシェアする

上へ