GB ゲーム開発覚え書き: スプライトを動かす1
Game, C, GameBoy前回でゲームボーイの基本的なことを知った。今回は GBDK(C 言語)での覚え書き。
実際にキャラクターを表示して、動かすゲームを作る。
画面の左上にプレイヤーがいて、十字キーで上下左右に動かし、画面右下にいるフレンドに接触すればゲームクリア。そんな大作。
最終的なコードはこちら。
※注意
C 言語特有の説明(型、配列、ポインタ、構造体、マクロ、ヘッダなど…)は省きます。
また、あくまで「ゲームボーイのゲーム」を作るための覚え書きなので、ゲームのロジックについては説明を割愛する場合があります。
タイルのおさらい
まず、キャラクターのグラフィックを描くために、「タイル」のおさらいをする。
タイルについて
前回で触れたように、グラフィックは、ピクセル単位でなく「タイル」という単位で保存される。
具体的には 8×8 ピクセルのひとかたまりが、 1 タイルとして扱われる。
これを本体の表示サイズで割ると、1 つの画面に 20×18 マス分のタイルを表示できることになる。
各タイルでは、最大 4 色が使用できる。
ID0〜3 の 4 種類あり、数字が高くなるにつれ濃度が高くなる。
スプライトについて
スプライトはバックグラウンドの上のレイヤーで、オブジェクトとも呼ばれる。
ID0 の色を透過色にできるので、自機などの移動するキャラクターなどに使われる。
スプライトは、8×8 か 8×16 のどちらかを 1 単位で表示できる。
ゲームボーイの画面で 8×8 は小さすぎるので、複数のスプライトを組み合わせて…例えば 4 つのスプライトで 1 つのキャラクターを表現する手法もある(メタスプライト)。
ゲーム内では一度に最大 40 個のスプライトが置ける。しかし、画面 1 行ごとに最大 10 個のスプライトしか置けない。
スプライトのタイルマップ
タイルデータを格納するのは VRAM。アドレスで言うと 8000〜97FF
の範囲。
その中で、スプライトのタイルマップは 8000-8FFF
に割り当てられる。
開発では、まずタイルとなるデータを、スプライトのタイルマップに割り当てないといけない。
スプライトの属性(OAM)
スプライトは FE00-FE9F
の範囲で、それぞれオブジェクト属性メモリ(Object Attribute Memory, 略して OAM)という 4 バイトぶんの情報を持っている。
FE00-FE9F
の 160 バイト ÷ OAM 4 バイトで、最大スプライト数が 40 個というわけだった。
4 バイトに何の情報が入るのかは、次回触れる。GBDK で開発する分には気にしなくても OK。
GBTD でタイルデータを作る
タイルデータの作成に便利なツールとして GBTD がある。
このツール自体は 1999 年の頃に作られた Delphi 製のオーパーツで、リンク元のライブラリは GBDK メンテナーがバグ修正したもの。
これで作成したデータは ASM, C などにエクスポートできる。
macOS では動かず、wine-crossover が必要。
詳しくは「macOS でゲームボーイ用ゲームの開発環境を構築する」の記事を参照。
タイルを C 向けにエクスポートする
GBTD を使い、タイル 0〜5 までの 6 タイルを作成した。
0 は主人公の正面顔、1〜4 は各向き、5 はフレンドキャラのタイル。
※ 1〜4 は存在を忘れていたので、これから開発するゲームでは使ってません。
メニューから export to
を選択する。
Export のメニューが開く。
まず、"File" フィールドの設定。
"Filename" はファイルの出力先。あとで include する。今回は Characters.c
にした。
"Type" は出力形式。"GBDK C file(*.c)" を指定する。
"Settings" フィールドはほとんどいじらない。
"Label" はとりあえず Characters
で。"Bank" は 0。
"From" と "To" は、出力するタイル番号の範囲。今回はタイル 0〜5 をエクスポートするので、"To" に "5" を指定する。
これで "OK" を押せば、Filename で指定されたパスに C ファイルが出力される。 そのファイルでは、タイルデータを格納した unsigned char の配列ができる。
src/Characters.c
const unsigned char Charcters[] =
{
0x7E,0x7E,0xFF,0x81,0xFF,0x81,0xFF,0xA5, // タイル 0
0xFF,0x81,0xFF,0x81,0xFF,0x81,0x7E,0x7E,
0x7E,0x7E,0xFF,0x81,0xFF,0xA5,0xFF,0x81, // タイル 1
0xFF,0x81,0xFF,0x81,0xFF,0x81,0x7E,0x7E,
0x7E,0x7E,0xFF,0x81,0xFF,0x81,0xFF,0x81, // タイル 2
0xFF,0x81,0xFF,0xA5,0xFF,0x81,0x7E,0x7E,
0x7E,0x7E,0xFF,0x81,0xFF,0x81,0xFF,0x8B, // タイル 3
0xFF,0x81,0xFF,0x81,0xFF,0x81,0x7E,0x7E,
0x7E,0x7E,0xFF,0x81,0xFF,0x81,0xFF,0xD1, // タイル 4
0xFF,0x81,0xFF,0x81,0xFF,0x81,0x7E,0x7E,
0x00,0x24,0x00,0x18,0x7E,0x7E,0xFF,0x81, // タイル 5
0xFF,0xA5,0x99,0xE7,0xFF,0x81,0x7E,0x7E
};
これをスプライトのタイルマップに設定するのが最初の目標。
スプライトの読み込み
プロジェクトの準備
ワークスペースとするフォルダ内に src
と release
と build
フォルダを作る。
その後、src/main.c
を作成する。
タイルマップを設定する
まずは、スプライトに使うタイルマップを設定する必要がある。
GBDK では set_sprite_data(開始番号, 読み込むタイル数, タイルマップ);
を使う。
今回は、GBTD でエクスポートした Characters.c
のタイル番号 0〜5 まで、6 つのタイルを設定する。
src/main.c
#include <gb/gb.h>
#include "Characters.c"
void main() {
set_sprite_data(0, 6, Characters);
}
これで make
してみる。ちなみに今回使用する Makefile
はこちら(gbdk
がホームディレクトリにあるとして)。
Makefile
CC = $${HOME}/gbdk/bin/lcc -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG
SRC = src/
BUILD = build/
RELEASE = release/
all:
$(CC) -c -o $(BUILD)main.o $(SRC)main.c
$(CC) -o $(RELEASE)rom.gb $(BUILD)main.o
release
に rom.gb
ができるが、この段階ではタイルマップを設定しただけなので、起動しても何も表示されない。
でも、BGB の VRAM ビューアーを見ると、0〜5 にタイルが設定されていることがわかる。
つづく
その2へ。