macOS でゲームボーイ用ゲームの開発環境を構築する
Game, C, GameBoyゲームボーイのゲームを作りたかったのでやった。
あと今のキーボードが Windows だと使いづらいので、開発体験的な意味でも全てを Mac で完結させたかった。
コーディングからカートリッジ書き込みまで、全て Mac でやるのが目標。
ゲームボーイのゲーム開発
ゲームボーイのゲーム開発には RGBDS か GBDK-2020 どちらかを用意することになると思う。
RGBDS はゲームボーイ開発用のツールチェーン。ASM で書かれたものをアセンブルする。
GBDK は ASM だけでなく C が書けるようになっているので、習得がかなり楽。
あとは WLA-DX というのがあって、そちらは GB や Z80 以外もサポートしているらしい。
ASM はゲームボーイ本体の知識が必要。C はイージーだけど ASM に比べればパフォーマンスが劣る。
とりあえず C を書きながら、少しずつ ASM も書けるように頑張っていく。
他に良いツールとしては GB Studio がある。Electron 製の GUI でゲームボーイのゲームが作れる。お行儀の悪いバグゲーを作れなさそうなので泣く泣く候補から外した。
環境、用意したもの
インテル製及び Apple Silicon(M1) モデルの MacBook で動作を確認した。
- macOS Big Sur 11.4
- GNU Make 3.81
- rgbds-0.5.1
- gbdk-4.0.4
- Apple clang version 12.0.5 (clang-1205.0.22.11)
- wine-5 CrossOver(GBTD-GBMB を使う場合)
- gtk 2.24.33(ppm を使う場合)
- Qt 6.1
- libftdi 1.5
インストール&コンパイル(GBDK の場合)
GBDK のリポジトリから macOS のバイナリをダウンロードして解凍する。
解凍してできた gbdk フォルダの中に hello-gbdk フォルダを作る。
そのフォルダの中に main.c
を置く。
gbdk/hello-gbdk/main.c
#include <gb/gb.h>
#include <stdio.h>
void main()
{
printf("HELLO WORLD");
}
そして Makefile を置く。
gbdk/hello-gbdk/Makefile
CC = ../bin/lcc
BINS = main.gb
all: $(BINS)
%.gb: %.c
$(CC) -o $@ $<
make
を実行する。
shell
cd gbdk/hello-gbdk
make
hello-gbdk フォルダに main.gb ができる。
インストール&コンパイル(RGBDS の場合)
好きなところに hello-rgbds フォルダを作る。
その後 brew で rgbds をインストールする。
shell
brew install rgbds
まず、ハードウェアのファイルを用意しておく。GB Dev にある hardware.inc を、hello-rgbds フォルダに入れれば OK。
次に、ASM を書く。GB ASM Tutorial の hello-world.asm を少しいじって main.asm
を作った。これも hello-rgbds フォルダに入れる。
(コードのライセンスは CC0 ですが、オリジナルのコードは GB ASM Tutorial のものであることをここに示します。タイルマップの部分などを変更しています)
hello-rgbds/main.asm
INCLUDE "hardware.inc"
SECTION "Header", ROM0[$100]
nop
jp main
ds $150 - @, 0
main:
di
ld a, 0
ld [rNR52], a
WaitVBlank:
ld a, [rLY]
cp 144
jp nz, WaitVBlank
ld a, 0
ld [rLCDC], a
ld de, Tiles
ld hl, $9000
ld bc, TilesEnd - Tiles
CopyTiles:
ld a, [de]
ld [hli], a
inc de
dec bc
ld a, b
or a, c
jp nz, CopyTiles
; Copy the tilemap
ld de, Tilemap
ld hl, $9800
ld bc, TilemapEnd - Tilemap
CopyTilemap:
ld a, [de]
ld [hli], a
inc de
dec bc
ld a, b
or a, c
jp nz, CopyTilemap
ld a, LCDCF_ON | LCDCF_BGON
ld [rLCDC], a
ld a, %11100100
ld [rBGP], a
Done:
jp Done
SECTION "Tile data", ROM0
Tiles:
db $00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00
db $66,$66,$66,$66,$66,$66,$7e,$7e
db $66,$66,$66,$66,$66,$66,$66,$66
db $7f,$7f,$60,$60,$60,$60,$7e,$7e
db $60,$60,$60,$60,$60,$60,$7f,$7f
db $60,$60,$60,$60,$60,$60,$60,$60
db $60,$60,$60,$60,$60,$60,$7e,$7e
db $7e,$7e,$c3,$c3,$c3,$c3,$c3,$c3
db $c3,$c3,$c3,$c3,$c3,$c3,$7e,$7e
db $83,$83,$83,$83,$b3,$b3,$b3,$b3
db $b3,$b3,$b3,$b3,$b3,$b3,$fc,$fc
db $7c,$7c,$62,$62,$62,$62,$7c,$7c
db $66,$66,$66,$66,$66,$66,$66,$66
db $7c,$7c,$66,$66,$62,$62,$62,$62
db $62,$62,$62,$62,$66,$66,$7c,$7c
TilesEnd:
SECTION "Tilemap", ROM0
;ウィンドウ表示がうまくいかなかったので一旦バックグラウンドで埋めている
Tilemap:
db $01,$02,$03,$03,$04,$00,$05,$04,$06,$03,
db $07,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
TilemapEnd:
hello-rgbds フォルダに Makefile を置く。
hello-rgbds/Makefile
all: build
build:
# アセンブル
@rgbasm -L -o main.o main.asm
# リンク
@rgblink -o main.gb main.o
# -v -p 0xFF でヘッダと ROM サイズを正しく修正してくれる
@rgbfix -v -p 0xFF main.gb
make
を実行する。
shell
cd gbdk/hello-rgbds
make
hello-rgbds フォルダに main.gb ができる。
スクリーンショット
hello-gbdk でコンパイルしたやつ。
フォントは printf
で出力されるもの。
RGBDS のやつ。
フォントは自前で用意したやつなので GBDK のものとは表示が異なる。
ツールを入れる
ASM や C だけで開発するのは厳しいので、ツールを導入する。
今回はこんなツールを使うんですよ、というさわりの紹介なので詳細には触れない。
エミュレーター
gb ファイルは、GB カートリッジに焼くか、エミュレーターを使用して起動できる。
開発中はデバッグも兼ねて、機能が充実したエミュレーターを使用することが多い。
GB のエミュレーターは BGB が有名。再現性が高く、残像の再現が可能で、デバッグ機能が充実している。
ただ BGB は macOS に対応していないので Wine で動かす必要がある。Wine については後述する。
macOS 向けのアプリケーションとしては、メモリと VRAM のチェックがそこそこにできる SameBoy がある。今回は SameBoy をメインで使ってみることにした。
タイルエディター、マップエディター
スプライトや背景の作成にタイルエディター、レベルデザインをするためのマップエディターが必要。
gbdk-2020/GBTD_GBMB を使うか、ppm を使う方法 2 種類がある。
まずポピュラーな gbdk-2020/GBTD_GBMB は、動作に Wine が必須。
Wine は Linux や Mac の環境で Windows アプリケーションを動かす互換レイヤー。
Wine 自体は 32bit なので、Catalina 以降の OS で動かない。現状 cross-over と言うのが 64bit になっているので、こちらの記事を参考に導入する。
次に、ppm というタイル & マップエディターがあり、そちらをビルドできる。
gtk2 が必要だけど、こちらは Wine なしで起動できる。
shell
brew install gtk+
cd ppm-master
make
sudo make install
使い方はよくわかっていない。
ウィンドウが小さいから、改造が必要かも。
作曲・mod変換ツール
.mod
を書き出せるトラッカーツールを使って、gbt-player の mod2gbt で ASM に変換できる。
それを gbt-player を使って鳴らす。
トラッカーは openMPT が定番らしい。でもどうせまた Wine なんでしょう、と言われたら悔しいので、macOS に対応した MilkyTracker というアプリケーションを使う。
UI のクセが強いがなんとか使える。ふいんきでやってる。
変換や再生を担う mod2gbt や gbt-player は、GBDK 向けでのメンテはされていない。
GBDK に依存する GB Studio は、少し前の 2.1 を使用してビルドしているようで、そちらのバージョンで試したところ変換できた。
一応 GBDK でも使えるだけであって、あくまで ASM 向けであることは意識しておかないといけない。
効果音ツール
ダウンロードした GBDK にはいくつか examples があり、その中の gbdk/examples/gb/sound/ をビルドすると、sound.gb が生成される。
これはサウンド再生のシミュレーターだけど、レジスタに対応した値を表示する便利な機能がある。
たとえば、sound.gb で「ブヨ〜ん」みたいな音を作り、画面下の NR10-14
の値が 17, 8C, 43, 41, 86
になっている時…。
GBDK では NR10〜NR14 をこのように記述することになる。
sample.c
NR10_REG = 0x17;
NR11_REG = 0x8C;
NR12_REG = 0x43;
NR13_REG = 0x41;
NR14_REG = 0x86;
フラッシャーとカートリッジ
開発したゲームを共有したりブラウザ上で動かしてもいいけど、カートリッジに焼かないとやった感が出ない。
CUBIC STYLE さんが BOOTH にてフラッシャーを販売しているので、そちらを購入した。
組み立て済みのフラッシャー本体と、32kb のフラッシュカートリッジがついてくる。
パッケージに惹かれたのが一番のところ。これは初代 GB ソフトのパッケージと同じサイズでもある。
注意点は gbt-player を使用すると、データがバンク 1 に入るので 64kb の ROM ができること。
今回は無理やり詰め込んで 32kb に押し込めた。やり方は後日機会があれば書く。
書き込みアプリケーション
書き込み用ソフトも CUBIC STYLE さんが配布しているけど、 Windows のみの対応。ただフォーク元の gbcartflasher 自体は Qt 製で macOS でも対応している。
それで、CUBIC STYLE さんのものをフォークして、こちらのリポジトリで Qt6 向けソースを作成した。
リポジトリから zip をダウンロードして解凍、中の gbcflsh_1.1_libftdi フォルダに移動。
Qt と libftdi を入れて、qmake && make
すれば gbcartflasher-master/gbcflsh_1.1_libftdi/release に app ファイルができる。
shell
brew install qt libftdi
cd gbcartflasher-master/gbcflsh_1.1_libftdi
qmake && make
次に、フラッシャーを Mac に USB 接続する。
ターミナルで system_profiler SPUSBDataType
を実行し、FT232R USB UART
が認識されていれば OK。
ついでに PID は 0x6001
VID は 0x0403
になっているか確認。
認識されていない場合は、VCP ドライバがいるかもしれない。
shell
FT232R USB UART:
Product ID: 0x6001
Vendor ID: 0x0403 (Future Technology Devices International Limited)
// 省略
これでゲームの読み書きができる。
終わり
これで macOS での GB ゲーム開発環境が整った。
今は「たこ焼きくん」という習作で色々とやってる。
ハードオフのジャンク箱で 108 円で売られてそうなアクションパズルを目指している。