以前、16MHz の Z80 を搭載した「VGS-Zero」という RaspberryPi Zero 2W のベアメタル環境での動作を前提とした8bitゲーム機を開発して公開しました。
今回、その次世代機として MC68030 と FM音源 を搭載した「VGS-X」を開発しました。
本書執筆時点の VGS-X はまだβ版(0.1.0)です。
README.md に掲載されている全ての仕様が実装済みの状態ですが、stable version (1.0.0) がリリースされるまではカジュアルに破壊的変更をする可能性がある点をご注意ください。
現在開発中の VGS-X の ローンチタイトルが完成したら stable version (1.0.0) がリリースされる予定(※ローンチタイトルの完成予定時期は未定)です。
VGS-Xは、VGS-Zero用のゲームを2本(Battle Marine, Battle AirForce)開発して得られた知見を活かして「私にとってよりゲームが開発し易いアーキテクチャ」を追及した最新のゲーム機です。
ざっくりとした特徴は次の通りです。
- CPU: MC68030
- Program ROM: 最大12MB の ELF32 形式
- Other ROMs: CHR, BGM, SFX (※Program ROM とは別領域)
- RAM: 1MB
- 解像度: 320x200 pixel (24bit color)
- Character ROM: 2MB (65536パターン)
- BG: 4面構造(キャラクタパターン方式とビットマップ方式に対応)
- Sprite: 最大1024枚, size: 8x8 ~ 256x256, 拡大縮小 + 回転に対応
- BGM: YM2149, YM2151, YM2203, YM2608, YM2610, YM2612 (VGM形式)
- SFX: 44100Hz, 16bit, ステレオ (PCM形式)
本書では、VGS-Xで「どのような流れでアーキテクチャの設計を行なったのか」を記します。
General Provisions
VGS-X は飽くまでも「私にとって」の最適解なので、全てのゲームクリエイターにとっての最適解だとは思っていません。
各々にとっての最適解を各々で探るのがベスト というのが私見です。
既存のゲーム機や主流のゲームエンジン(UnityやUnreal Engineなど)がベストと考えた方が賢明だと思いますが、既存のゲームエンジンでは満足できない foolish なゲームクリエイターさんも一定数居ると思います。
そこで、私がどのような流れでゲーム機を設計したのかを(設計思想中心で)文書化してみようというのが本書の試みです。本書が 「僕が考えた最強のゲーム機」 を創作する一助になれば幸いです。
VGS-Zero のライセンスはかなり複雑になってしまいましたが、今回は MIT + 修正BSD (BSD-3) というとても緩いライセンスで提供しているので、vgsxリポジトリをforkして自分好みの仕様に書き換えるのも容易だと思います。
CPU Selection
まずは、ゲーム機の心臓部となる CPU を選定する必要があります。
既存のCPUを使うのか、新たなセルを開発するのか、様々な選択肢があると思います。
私が今回 MC68k を採用することは前世代機の VGS-Zero を開発する以前からの決定事項でした。
以下、MC68k を採用した経緯(昔話)を記します。
VGS-Zero が採用した Z80 は「8bitの中では」とてもプログラミングし易い良い CPU でした。8bit CPU でありながらペアレジスタを使うことで 16bit の演算も(他の 8bit CPU と比べれば)比較的簡単にできます。
ただし、私がプログラマとしてのキャリアを開始した1993年ごろ(当時中学生)は既に 8bit の時代は終わっていたので、個人的には 8bit CPU に思い入れというか馴染みみたいなものはそれほどありません。
私よりもう少し上の世代の方々であれば、MSX の功績により安価なパソコン(マイコン)を持つことが容易だったと考えられるので、MSX 経由で Z80 に慣れ親しんだ方々が多く居るはずです。
参考までにMSXで最安値だった機種(カシオ MX10)の値段は19,800円だったようです(参考記事)。ファミコン(14,800円)よりも少し高いですが、お年玉をかき集めるなどすれば当時の小学生でも可処分所得の範囲で購入できそうな金額感だと思われます。
MSXの最大の功績は「リーズナブルな価格でパソコンを供給したこと」だと思っています。しかし、価格競争が激化したことで協賛会社の撤退を促して衰退していった側面もあったかもしれません。それでも価格が安かったからこそ「多くのクリエイターを生み出すこと」に成功した偉大なパイオニアだと思っています。
1993年当時、MSXは完全に衰退していたため、私が通っていた田舎のパソコンショップでは取り扱っていませんでした。
MSXの供給が終わったことでPC-98シリーズなどのものすごく高級なパソコンしか市場に残らなかったため、当時パソコンを所有していたのはブルジョアジー階級の裕福な方々に限られていたものと思われます。
その当時のPC-9801の価格帯はだいたい40〜50万円前後だった記憶です。パソコンが一般階級の家庭にも普及するのは1990年代後半(主に1995年のWindows95以降)になります。
幸い、私が通っていた公立中学校には30台ほどのパソコン(PC-9801)があり、パソコン部に入ることでそれらを自由に使うことができました。パソコン部ではハイパーキューブを用いて各種集計業務(教師の仕事?)をしたり、技術(選択教科)の教師にプログラミングの指導をしたり、マイコンBASICマガジン(ベーマガ)に掲載されていたN88日本語BASIC用のゲームプログラムを目視で打ち込んで遊んだりしました。
ベーマガを通じて存在だけは知っていたMSXやX68000などのパソコンではスプライトが扱えたので、PC-9801(Bitmap方式のグラフィックと単色の文字表示のみ)では作るのが難しかったアクションゲームを簡単に開発できて羨ましかったことを今でも鮮明に覚えていて、その記憶が VGS 創作の源泉だと思われます。
VGS-Zeroの記事で「VGSは私にとってゲームが開発しやすいプラットフォームの創出」を目的としているようなことを書きましたが、MSXやX68000を羨望の眼差しで眺めていた中学生時代の私の供養 という裏の任務もあって、MSX (8bitアーキテクチャ) については VGS-Zero で充足できたものと思います。そして、X68k (16bitアーキテクチャ) についても供養しておこうと考えるのはごく自然な流れです。
「無いものねだり」は創作意欲の強い動機になります。
始めは ただ欲しかった
そのような背景から、CPU には馴染みがある 80186 や 80286 ではなく MC68k を採用することになりました。
MC680x0 は CPU ではなく MPU と呼ぶべきかもしれませんが、本書では全て CPU と表記します。
また、MC68k のレジスタは 32bit なので、「エミュレーションの動作効率」という観点では 80286 (16bit レジスタ) よりも優れていそうだった という技術的な判断も "当初は" ありました。
MC68kはビッグエンディアンで、基本的に現代のCPUはリトルエンディアンなのでエンディアン変換のオーバーヘッドが発生します。つまり、実態的にはエミュレーション効率がx86より若干悪いかもしれません。ちなみにそのことは、実際にMusashiを組み込んでELFバイナリを動かすテストをしたタイミングで気づきました。要するに、「MC68k = Big Endian」ということすら知らない程度に私のMC68kについての専門知識は浅いです😅
レジスタが32bitなのに「16bitのゲーム機」なのか?
という無粋な疑問もあったのですが、MC68000 を搭載したゲーム機であるメガドライブは本体に金色の文字で堂々と「16-BIT」と刻まれているので、「MC68k を搭載したゲーム機はきっと 16bit である」と信じておくことにします。
なお、VGS-Xが採用しているのは MC68000(アドレスバスが24bit)ではなくX68kの最上位モデルが採用していた MC68030(アドレスバスが32bit)なので、「それなら32bitゲーム機では?」みたいな疑問は黙殺しておきます。
誰が何と言おうと VGS-X は 私が求めた究極の16bitゲーム機 です。
MC680x0 のエミュレータについては Musashi (MIT ライセンス) が良い感じだったので、今回は自前制作せず既存の OSS を利用させていただくことにしました。
MC68kのCコンパイラについては GCC (m68k-elf-gcc) を利用できます。
Linux だと m68k-elf-gcc を準備するのがやや面倒ですが、macOSであれば Homebrew で配信されているので手軽にインストールできます。
brew install m68k-elf-gcc
macOSとLinux向けのm68k-elf-gccのインストール手順については ドキュメント で詳述しておきました。m68k-elf-gcc 以外にもデバッグ用のエミュレータを動作させるために SDL2 のインストールも必要です。
VGS-Zero の時と同様、開発環境の推奨OSは Ubuntu Linux or macOS で、Windows は対応が面倒なのでサポートしません。(※ランタイム環境については Windows もサポートします)
CPU Performance
VGS-Zero では 16MHz の Z80 を搭載しましたが、VGS-X では 固定のクロック上限を設けない仕様 にしました。
VGS-X には V-SYNC を待機(同期)する入力命令(低水準I/O)があり、VGS-Xエミュレータはその入力命令を検出した時に VRAM の内容を参照してサーフェース(実ディスプレイ)への出力を行いつつ 60fps の同期を行います。
while (1) {
my_proc(); // 画面描画 (VRAM 更新) などの処理を行う
vgs_vsync(); // V-SYNC を待機(このタイミングで画面表示 & 60fps の同期)
}
これによりホストコンピュータの限界性能までプログラムを動かすことができます。開発するゲームのベースラインの決定責務をゲーム開発者へ委ねた(丸投げした?)とも言えます。
この仕様にすることのデメリットとしては次のようなものがあります。
- スキャンライン位置と同期した描画表現(ラスタースクロールやスプライトダブラーなど)ができない
- 処理落ちを前提としたゲームデザインができない
逆に次のようなメリットが考えられます。
- ホストコンピュータの限界性能まで動かせる(目的とするアーキテクチャを実現できる)
- 画面描画のエミュレーション効率が良くなる(補足を後述)
描画エミュレーションの効率について補足しておきます。
通常のゲーム機エミュレータの場合、スキャンラインごと(より正確なエミュレーションをしたければピクセルごと)に描画処理をエミュレーションする必要がありますが、一括で全画面の描画処理を行なった方が処理効率は圧倒的に良いです。
エミュレーション効率が良くなることで「より多くのBGレイヤーを持つこと」や「より多くのスプライトを表示すること」などができ、BGレイヤーが多ければラスタースクロールは(ほぼ)不要になり、より多くのスプライトが表示可能であればスプライトダブラーも不要になります。
X68k だと全画面で 128枚(1スキャンライン内では32枚)のスプライトを表示できたようですが、VGS-Xでは1024枚のスプライトを表示できるので、変態コーディングをしなくても スプライトオクタルプラー (※X68k比で8倍) です。
Memory Map
搭載 CPU を決定後、CPU の仕様に適したメモリマップを設計しました。
MC680x0 は 24bit (16MB) の物理メモリ空間にアクセスできるらしいので、最初に次のような大枠のメモリマップを設計しました。
| Address | Size | Description |
|---|---|---|
0x000000 ~ 0xBFFFFF
|
12MB | Program (ELF32 module) |
0xC00000 ~ 0xEFFFFF
|
3MB | mmap (I/O) |
0xF00000 ~ 0xFFFFFF
|
1MB | Work RAM |
Program
メモリの先頭12MB(0x000000 ~ 0xBFFFFF)をプログラム用の ROM 領域としました。
メモリマップの表でも書いていますが、この領域には MC68030 のバイナリコードを直接載せるのではなく ELF32 形式のバイナリを展開する仕様 にしています。
VGS-X カーネル(ネイティブBIOS?)にシングルタスク専用のLinuxのような機能(ELFをパースしてメモリリロケーションやプログラムカウンタの初期化などを行う機能)が実装されているので、m68k-elf-gcc でコンパイル+リンクした実行モジュール(a.out)をプログラム・メモリ(0x000000 ~ 0xBFFFFF)にロードすればそのまま動かすことができます。
VGS-Zeroは当初「C言語で開発できる」という点を推していたのですが、クロスコンパイラ(SDCC)のコンパイル速度と最適化性能があまり実用的ではなかったので、結果的に自前のZ80アセンブラを開発した上で Battle AirForce はフルアセンブリ言語で開発しました。
フルアセンブリ言語での開発は面白いのですが生産効率がとても悪いです。
MC68kのアセンブリ言語は「高級言語並に開発し易い」という意見もチラホラ耳にしますが、どう考えてもC言語の方が開発し易いです。そして、MC68kであれば(過去のバージョンではありますが)GCC; GNU Compiler Collection が対応しているのでコンパイル速度や最適化性能などの品質について実用的な水準を期待できます。
VGS-Xのプログラム領域はGCCが出力するELF形式をそのまま配置する仕様にすることでアーキテクチャとして「フルGCCでの開発」を前提としていることが明確になるかもしれません。
最初からフルC言語での開発を前提としているので、CPUは慣れたx86ではなくMC68kで良い(極論なんでも良い)ということになります。
また、「フルC言語での開発」を可能にするため、全ての低水準I/Oはメモリマップで行う設計にしました。
そもそも、MC68k には I/O 命令が無いようです。
素晴らしい。
x86 にはI/O命令があります。I/O命令があっても使わなければ良いだけの話ではありますが、冗長な命令は無い方が良いです。8bit CPU にはアドレス空間が 16bit (64KB) しかなかったので、I/O 命令を持つことの意義はあったと思います。そのため mmap I/O を前提とした MOS6502 よりも Z80 に人気が集まったことについて理解できるのですが、16bit CPU 以降の時代の IN 命令や OUT 命令は不要(冗長)だと思っています。
「極論CPUは何でも良い」と先述しましたが、折角なら美しい CPU の方が良いので MC68k を採用できて良かったです。
CPU が穢れる根本的な原因は 下位互換性の維持 です。だから、x86 にはリアルモードやプロテクトモードみたいな気持ち悪い仕様が当然のように残り続けているものと想定しています。
ちなみにリアルモードやプロテクトモードは2023年発表のx86-sでようやく廃止が発表されました。(ただし、x86-sは2024年12月に開発が放棄されました)
下位互換性を維持しなければ「目先の利益」が目減りしてしまうのですが、下位互換性を維持してしまうと「将来の発展」を阻害するリスクを積み残すことになるというジレンマがあるので、ビジネス的な判断が難しいところだと思います。
「目先の利益を優先」というとものすごく悪いことのように思われがちですが、経営判断としては別に悪いことではありません。むしろ、「目先の利益を放棄したために赤字転落」よりは遥かにマシです。ただし、大きく発展する可能性があるのは前者路線(目先より将来を優先)です。そのため、ギャンブラー寄りの投資家はその路線を好む傾向があります。(当たる確率は低いが当たった時の倍率が高い万馬券のようなもの)
余談ですが、私は設計が穢いと感じたIntel(後者路線?)の株を1株も持っていなくて、逆に設計が美しいと感じたARM(前者路線?)の株は親会社の財務的な事情により一部市場放出された2023年に少量ですが購入して現在も持ち続けています。結果的にIntelは10年前よりも時価総額を落とし、ARM株は公開時点から約3倍程度になったので投資判断としては正しかったように思えます。しかし、ビジネス的にどっちの路線が正しいのかは正直よく分かりません。
結局のところ、株もビジネスも 当たるも八卦 当たらぬも八卦 かなと😅
I/Oを全てメモリマップにすることで、低水準入出力を全て高級言語(C言語)で記述することができるので「フルC言語でのゲーム開発」に適した 美しいアーキテクチャ を設計することができます。
I/O (mmap) Design
0xC00000 ~ 0xEFFFFF の I/O (mmap) は下表のように設計しました。
| Address | Size | Description |
|---|---|---|
| 0xC00000 ~ 0xCFFFFF | 1024KB | Name Table or Bitmap |
| 0xD00000 ~ 0xD0FFFF | 64KB | OAM |
| 0xD10000 ~ 0xD1FFFF | 64KB | Palette |
| 0xD20000 ~ 0xD2FFFF | 64KB | VDP Register |
| 0xD30000 ~ 0xDFFFFF | 832KB | Reserved |
| 0xE00000 ~ 0xEFFFFF | 1024KB | System I/O + User I/O |
ざっくり、前半 2MB (0xC00000 ~ 0xDFFFFF) を VDP (VRAM + Register)、後半 1MB (0xE00000 ~ 0xEFFFFF) がその他という感じです。
この辺りまでアーキテクチャが設計できた段階で VDP の設計を始めました。
Screen Resolution
VGS-X の画面解像度は 320x200 ピクセル (固定) という仕様にしました。
ちなみに VGS-Zero は 240x192 ピクセル (固定) なので、VGS-Zero と比較して若干横長 になっています。
私は縦スクロールの shmup (FPS ではないシューティングゲーム) が好きなので、どちらかといえばあまり横長にしたくなかったのですが、この解像度を採用した唯一の目的は SteamDeck ファースト です。
SteamDeck の解像度は 1280x800 です。
320x200 は SteamDeck の縦と横を 1/4 にしたサイズなので、SteamDeck で 画面に隙間がなく、尚且つ ピクセル欠けが発生しない 整数倍での拡大表示ができます。
なお、任天堂Switch や PlayStation の画角は 16:9 なので、それらのゲーム機で 320x200 (16:10) の画面を拡大表示すると左右に若干黒い隙間ができてしまいます。
また、任天堂Switch や PlayStation の標準的な解像度は 1080p (1920x1080) や 4K (1080pの縦横を2倍) なので、画面にフィットさせた形で拡大(アスペクトフィット)をしてしまうとピクセル欠けも発生してしまいます。(1080 ÷ 200 = 5.4)
将来的には 任天堂Switch や PlayStation でゲームを販売したいと思いつつ、当面は(ヒット作を出すまでは)Steam で販売することしかできないので、SteamDeck ファーストの画角 が大半の同人ゲームプログラマ(インディーゲームプログラマ)にとってベストな解像度だと考えました。
また、PC-9801 も同じ画角だった(※解像度は 640x400 だった) ので、PC-9801 でのゲーム開発に慣れ親しんだ方々にとっては扱い易い解像度かもしれません。私は長らく PC-9801 向けのゲームは開発してないのでとてもフレッシュな気分ですが😅
ちなみに、(ノッチを搭載する以前の)MacBook の画角も 16:10 (2560x1600) なので、MacBook(のセーフ領域)でもピクセル欠けが無い全画面表示をすることが可能です。
Battle Marine と Battle AirForce の販売実績を見る限り、売り上げ本数は Windows >>> Linux > macOS (Windows が 9割ほど) なので、macOS 対応のプライオリティはそれほど高くはありませんが...
Graphics
VGS-Zero ではBG, FG, スプライト(3層構造)のCG表示機能を実装しました。
BG は主にゲームの背景描画、スプライトは画面上を動き回る自機や敵機、FGはスコアなどのUI表示という使い方を想定しています。
VGS-Zero 版の Battle AirForce を開発した後で、それをゲームボーイアドバンス(GBA)へ移植してみたのですが、GBAではBGが4層構造(+スプライト)という形でした。
GBA版Battle AirForceはSteamでの購入特典としてROMファイルを配っています。
https://store.steampowered.com/news/app/3476490/view/547859909314609367
GBA版を開発し始めた時「BGが4層も要るん?」という疑問があったのですが、GBA版の開発を終えた後「BG4層がメチャクチャ便利」だと実感しました。
という訳で、VGS-XのBGはGBAと同じ4層構造にしました。
また、VGS-XのBGは従来(VGS-Zero)と同じ「キャラクタパターン方式」に加えて「ビットマップ方式」もサポートしてます。
コンピュータ・グラフィックス(CG)の描画方式は大きく分類すると次の3方式があると思っています。
- キャラクタパターン方式
- ビットマップ方式
- ポリゴン方式
個人的にゲームを一番作り易いのは「キャラクタパターン方式」だと思っているので、VGS-Zero では BG, FG, スプライトの 全て がキャラクタパターン方式という仕様にしてます。
ただし、「ビットマップ方式もあった方が便利」だと思っていて、VGS-X では BG が4層もあるので「特定のBG層をビットマップ方式にも変更できるようにしたい」と考えたので実装してみました。
ビットマップ表示を実装してみたところ、MSX2(V9938)のコマンドのような図形描画も欲しくなったので、図形描画のハードウェア機能も実装しています。(図形は点、線、矩形、塗りつぶし矩形、キャラクタパターンの描画に対応)
これらの図形描画機能はVGS2(VGS-Zeroの前世代)でも提供していたので、結果的に VGS-X で先祖返りした形になります。
GBAでのゲームプログラミングをしてみて「BGが4層であること」以外にとても便利だと感じたのがスプライトの アフィン変換機能 です。
GBAではアフィン変換機能を用いることで拡大・縮小や回転などができます。
ハードウェア回転機能があることでキャラクタパターンの回転画像を準備する必要がなくなるので、あるととても便利です。
そこで、当初VGS-Xでもアフィン変換に対応しようとしたのですが、アフィン変換を行うには結構な量の行列演算を行う必要があるので、オーバーヘッド面で微妙だと感じました。
CUDA コア (GPU の行列演算ユニット) を使えば高速な行列演算が可能ですが、CUDA コアを扱う API (Vulcan など) を使うとプラットフォーム間でのエミュレータコアの移植性が落ちてしまいます。
私にとって必要だったのは汎用的なアフィン変換ではなく「回転機能だけ」で、回転機能なら三角関数の演算だけで実現できるため、VGS-X では三角関数を用いたスプライトのハードウェア回転機能を実装しました。
なお、当初「回転機能だけあれば良い」という謙虚な姿勢だったのですが、人間とは欲深い生き物でハードウェア拡大縮小機能も欲しくなったので実装しました。
上記のツイートでも言及してますが、回転角度と拡大縮小率を OAM に指定する仕様です。
参考: VGS-XのOAM
typedef struct {
uint32_t visible; // Visible (0 or not 0)
int32_t y; // Position (Y)
int32_t x; // Position (X)
uint32_t attr; // Attribute
uint32_t size; // Size (0: 8x8, 1: 16x16, 2: 24x24, 3: 32x32 ... 31: 256x256)
int32_t rotate; // Rotate (-360 ~ 360)
uint32_t scale; // Scale (0: disabled or 1 ~ 400 percent)
uint32_t reserved[9]; // Reserved
} OAM;
個人的にはこの点がとても重要です。
GBAのアフィン変換機能はものすごく便利なのですが、指定方法がものすごく複雑 という不満があります。GBAのアフィン変換機能の仕様は以下のドキュメントでとてもわかり易く解説されています。
GBAでは、VRAMにアフィン変換のパラメタ(PA, PB, PC, PD)を要素に持つテーブルを定義しておき、OAMで使用するアフィン変換テーブルの要素インデックスを指定することでスプライトのアフィン変換ができます。
アフィン変換のパラメタテーブルの要素数の上限(32)はスプライトのOAM数(128)よりも少ない点を注意する必要があります。
それに加えて、「PA, PB, PC, PDの指定がどのように目的とする変形をするか」(指定方法)が人間には分かり難いという点が最大のデメリットかと思われます。
良い大学を出て任天堂で働いているようなものすごく頭が良い人なら「xxxへ変形したければPA, PB, PC, PDにはxx, xx, xx, xxを指定すればOK」と空で瞬時に適切な解を導き出せるのかもしれませんが、残念ながら中学生の頃の私はそこまで賢くありません。
一方、VGS-X では、
「rotateを指定すれば回転、scaleを指定すれば拡大縮小」
という中学生の頃の私でも確実に理解できる仕様にしました。
アフィン変換と比べて複雑なトランスフォームができませんがとてもシンプルです。私は「多機能だが使い方が複雑なデザイン」よりも「目的とする機能をシンプルに実現できるデザイン」を好みます。
また、私が考える「シンプル」の基準は「中学生の頃の私」です。
Sound
VGS-Zero では当初 VGS; Video Game Sound という私が開発した独自音源チップ(固定波形の波形メモリ音源方式)を採用しました。VGS 形式のデータは mml で記述しますが、この mml も独自形式です。
私は当初これで満足していたのですが、FamiStudioというファミコン用の作曲ツールがとても良い感じだったので、NSF 形式の再生に対応しました。
作曲ツールの開発はものすごく大変なので、サードパーティー製のツールを積極的に使えるようにしたいところです。
NSF 形式は、APU (Audio Processing Unit) のレジスタ操作や同期処理を行う 6502 のプログラムコードなので、NSFを再生するには映像処理を除くファミコンエミュレータ相当の実装が必要になります。そのため、オーバーヘッドがやや高いです。エミュレータコアモジュールの依存ソースコードが増えすぎる点も微妙でした。
その後、VGMというフォーマットの存在を知ったので NSF を廃止して移行しました。
VGM; Video Game Music は、様々な音源チップのレジスタに書き込む値とサンプル単位の同期時間から構成されるシーケンシャルデータです。
チップチューン音源界隈ではこれがデファクトスタンダードな仕様のようなので、様々な音楽制作ツールが VGM 形式のエクスポートに対応しています。
デファクトスタンダードな形式に対応しておけば、外部の優秀な音楽制作ツールを使える幅が広がります。
私が独自開発した VGS; Video Game Sound を通常の音源チップと同様のレジスタ I/O に対応させて VGM に対応させることも出来なくはありません。しかし、音楽制作ツールでVGSの再生に対応するには音楽制作ツール側での改修も必要になり、当然ながらそれは現実的な選択肢ではありません。
そこで、VGS-Xでは VGS; Video Game Sound を思い切って廃止して、VGMが対応している FM音源 を搭載することにしました。
ymfm という mame ベースの FM音源エミュレータ が 3箇条BSDライセンス で公開されていたことも VGS を廃止しても良いと判断できた理由のひとつです。
初代 VGS を開発した当時(2011年ごろ)、音源は自前制作ではなく使い慣れた YM2203 (OPN) エミュレータを搭載する方向で検討していました。
その当時のOSSのFM音源エミュレータとしては fmgen が有名だったのですが、fmgen には「無許可での商用禁止」などの条項があります。そのため、自由な商売を許可している VGS では fmgen(商用利用が許可制)を採用することが 不可能 です。
「一定のルール下での自由な商売」は資本主義社会をハックする上で不可欠な要素なので、VGS-Zero もそうですが、VGS-X でも商用利用についての制限をしていません。むしろ「ライセンスフィーは一切不要」と明言した上で商売することを(もちろん強制はしていませんが)推奨しています。
絵や音楽やゲームなどの「コンテンツ」を創作できる人々(クリエイター)の商売の自由を奪うことは資本主義社会というルール下のゲームでは悪手だと思っています。
何故ならコンテンツは極めて少ない原材料費(デジタル・コンテンツなら0)で資本を生み出すことができるから 資本の生産効率 が良いので。
ただし、コンテンツがヒットする確率はものすごく低いため、ヒットするコンテンツを創出するには「手数を増やすこと」が必要になります。
そのため、画家の才能があると思われる人々に筆や絵の具を売って小銭を稼ぐより、彼らに筆や絵の具を無料で与えた方が「生み出す総資本」を多くできる可能性 (生産性) が高いと私は考えています。
筆や絵の具を売った方が「簡単に儲かる」ので、商業的に不自由なライセンス(商用利用を許可制にしてライセンスフィーを徴収する商売など)を否定するつもりはありませんが、複製製造に原材料費が掛からないデジタルな世界では既に「クローズドな有料のツール」が衰退して「無料のOSS」が支配的な地位にあります。(例えば Linux, Git, LLVM など)
その点を踏まえて初代VGSの時に商業的に自由なライセンスで扱える独自音源を自作したのですが、ymfm(3箇条BSD)なら商用利用ができるので「独自仕様でなければならない理由」がありません。
ymfm は OPL, OPN, OPM, OPQ, OPZ など様々な FM音源 をサポートしてますが、OPL と OPNA のリズム音源については著作権侵害のリスクがあると思われたので、それらとVGMが対応していないモデルを除外したFM音源(以下)のVGMをサポートすることにしました。
- YM2149 (SSG)
- YM2151 (OPM)
- YM2203 (OPN)
- YM2608 (OPNA) ※リズム音源なし
- YM2610 (OPNB/OPT)
- YM2612 (OPN2)
これらの FM音源 に対応した VGM は、Furance Tracker という作曲ツールで作成することができます。Furnace Tracker は DAW などのシーケンサーに慣れた人にとっては扱いが難しいかもしれませんが、MML に慣れた人にはとても扱いやすい作曲ツールです。
実際の再生例としては以下の通りです。
上記ツイートのサンプルでは YM2612 の 2ch を使って簡単なベースとドラムのパターンを再生しています。
YM2203 + YM2608 + YM2612 みたいなマルチ音源構成は、VGS-X と Furance の両方が対応しているので可能です。ただし、チャンネル数が多くなると各音が相対的に弱くなることに加え、作曲やデータを打ち込む労力も増えてしまうため 最大6和音ぐらい が色々な意味でベストなバランスだと思います。
実際、着メロ全盛期の頃に多チャネルのFM音源が流行していたのですが、16和音とかになるとチャンネル数が多すぎるためか若干音割れしていて音が汚かった記憶です。
なお、効果音については VGS-Zero と同様に PCM を合成再生できます。(効果音用のチャンネルマスクは不要 & 音源ドライバの開発も不要です)
効果音についての VGS-Zero からの変更点としては PCM の波形サイズが 44100Hz のモノラルからステレオに変わりました。(一部FM音源がステレオ用だったので)
Gamepad
VGS-Zero では、「マニュアルを読まなくても簡単にゲームをプレイできること」を目的として方向パッド+2ボタン+2コントロールというシンプルなゲームパッドをサポートしました。
実は、4方向 (4bit) + 2ボタン (2bit) + 2コントロール (2bit) なら 8bit の範囲に収まるので 8bit レジスタで扱いやすいという事情もあったのですが、VGS-X ではそれについて気にする必要がありません。
VGS-Xは「SteamDeckファースト」で開発しているので、SteamDeckのコントローラを基準にVGS-Xの標準ゲームパッドを検討しました。
検討の結果、VGS-Xで使用できるボタン・レイアウトを次のように定義しました。
D-Pad
D-Pad は UI のカーソルやゲーム本編でプレイヤーの移動に使うことを想定しています。
なお、十字キーと左アナログスティックの操作は等価として、アナログスティックとしての使用(右アナログスティックの使用)については 戦略的に排除 しました。
アナログスティックに対応してしまうと PC キーボード での操作が出来なくなってしまいます。
Steam は PC ゲームプラットフォームであるため「キーボードのみでも操作できること」を求めるユーザー(キーボーダー?)が結構多く居て、私自信もキーボーダーだった時期があるため、キーボードのみでも操作できることは必須要件と判断しました。
ABXY
ABXYは次のような役割を想定しています。
- A: UI操作の決定(Steam BigPictureモードの操作と等価)
- B: UI操作のキャンセル(Steam BigPictureモードの操作と等価)
- X: 連打が必要な操作(STGのショットなどを想定)
- Y: 予備(基本的に使わない)
Other
以下のボタンは意図的に割り当てないようにしてます。
- Back (PS: share, SW: minus)
- L/R (L1/L2, R1/R2)
これらのボタンはシステム割り当てと被るので、アサインできてしまうと不都合が生じます。例えば、スクショや動画を撮影したいのに意図しない操作をしてしまったり、macOSだと Backの入力 がOSに奪われてしまったりします。
Design
依然として「マニュアルを読まなくても簡単にゲームをプレイできること」は重要だと考えているので、あまり複雑なボタン仕様にすることはオススメしません。
そういった意味ではVGS-Zeroのシンプルな仕様の方がむしろ良かったと今でも思っています。
しかし、VGS-Zeroの仕様だと微妙に Steam BigPicture モードの UI 操作とアサインの乖離が生じてしまうように感じられたので、「SteamDeckファースト」という観点では若干微妙だと感じられました。
そこで、SteamDeckの標準的なボタンアサイン(XBOX方式)に 必要最小限の範囲で 寄せることを決断しました。
なお、各プラットフォームのゲームパッドでのアサインは次のようになります。
| VGS-X | Keyboard | Switch | PlayStation | Typical Usage |
|---|---|---|---|---|
| D-pad | Cursor | D-pad | D-pad | Move |
A |
Z | B |
Cross |
Enter, Bomb |
B |
X | A |
Circle |
Cancel |
X |
A | Y |
Rectangle |
Attack |
Y |
S | X |
Triangle |
Unused |
Start |
Space | Plus |
Options |
Start / Pause |
※日本版 PlayStation4 については決定を Cross にアサインする設定(海外版PlayStation4 や PlayStation5以降の標準)を想定しています。

