東方VGS実機版をより「ゲーム機」っぽくしてみる(前編)
前回記事(下記)で紹介した拙作の同人ハードウェア「東方VGS実機版」ですが、これをより「ゲーム機」っぽくするための改修を進めてみました。
東方VGS実機版は東方VGS専用のハードではなく、新しいゲーム機を創りそのローンチタイトルとして東方BGM on VGSを完全移植という(とても面倒くさい)文脈で開発しています。
前回の記事でも言及していますが、リリース時点では東方VGSのファームウェア実装に必要な最小限の機能しか実装しておらず、私がビデオゲームを創るために必須だと思っている以下の3つの機能実装を省略しています。
ゲーム向けのグラフィックス描画機能
効果音の再生
ゲームパッド
なお、ゲームパッドについては本書執筆時点でまだ対応中(部品集めや技術選定の途中)なので、まずは完成している1〜2の詳細について文書化してみました。
1. ゲーム向けのグラフィックス描画機能
ゲームに関係するコンピュータ・グラフィックスの描画機能は、大別すると次の3種類のテクノロジーが主流という認識です。
キャラクタパターン方式
ビットマップ方式
ポリゴン方式
ベクタースキャン方式?
すみません、よく分かりません。
なお、上述のテクノロジー区分は便宜上私が勝手に命名と区分をしたものなので、現時点のゲーム機関係の論文などでは見られないかもしれません。
そのため、先ずは(少しだけ長くなりますが)各テクノロジーの定義を論述します。
(1) キャラクタパターン方式
オシロスコープやTTL等を除けば最も古典的な方式の一種で、例えば1976年に発売されたApple Iは24行40列の文字を表示できましたが、この方式に分類されるものと考えられます。
キャラクタパターン方式には、メモリ上に少なくともパターンテーブルとネームテーブルと呼ばれる2種類の領域が必要です。
パターンテーブル: キャラクタの画像データ(ビットマップ形式)のレコードを持つ線形構造のテーブル
ネームテーブル: 画面に出力するキャラクタ番号等の属性情報レコードを持つ行列構造のテーブル(行列の位置=画面上の表示位置)
なお、キャラクタ(文字)パターン方式は、元々はグラフィックスではなくテキストを表示する用途のものでした。
パターンテーブルがRAM; Random Access Memory(読み書き可能なメモリ)ではなくROM; Read Only Memory(読み取り専用メモリ)にあり、プリセットされたキャラクタ(文字)のみ表示できるコンピュータも存在します。(PC-98など)
なお、PC-98ではテキスト画面を使って高速なローレゾ・グラフィックス表現も可能で、それを使った例外的なゲームも幾つか存在します。(親父王など)
また、外字機能を駆使してテキスト画面で高精度なグラフィックスを描画した変態(※褒め言葉)も居たかもしれません。
しかし、PC-98のキャラクタパターン方式の画面表示機能は基本的にはテキストを表示するためのもので、グラフィックスは後述するビットマップ方式で表示するのが一般的です。
一方、キャラクタパターン方式をメインのグラフィックス描画機能として使用するディスプレイICチップも存在しました。
(TMS9918シリーズ)
1979年に発売されたテキサス・インスツルメンツ社製のホームコンピュータTI-99/4に搭載されたVDP; Video Display Processor「TMS9918」は、パターンテーブルがVDP内部に搭載されたRAM領域(VRAM; Video RAM)にあり、自由に描かれたキャラクタパターンをネームテーブルでタイルパターンのように並べることでグラフィックスを表示することができました。
TI-99/4はあまり売れなかったものの、1981年に発売された後継機「TI-99/4A」は大ヒットし、TI-99/4Aに搭載されたVDP「TMS9918A」は後に様々なゲーム機等へ採用されました。
日本では1983年に発売されたSG-1000(セガ)やMSX(ASCII・Microsoft)などで採用されています。
1985年に登場したSG-1000とMSXの後継機(セガマークIIIとMSX2)では、TMS9918Aの技術を基礎にしつつ進化したVDPが搭載されていますが、ゲーム機であるセガマークIIIはキャラクタパターン方式のみを強化し、ゲーム機ではないMSX2は主にビットマップ方式を強化する異なる進化系譜を辿ることになります。
キャラクタパターン方式は、当時のゲーム機のグラフィックス描画方式の花形でした。
(TMS9918Aの特徴)
TMS9918Aは、TMS9918にMODE2と呼ばれる画面モードが新たに追加され、MODE2では全画面(256x192ピクセル)に異なる8x8ピクセルのキャラクタパターンを表示できました。
SG-1000やMSX向けの市販ゲームの大半はMODE2が使われています。(しかし、個人的には画面を3分割する必要があるMODE2よりも、シンプルなMODE0の方がゲームを作りやすい気がします)
TMS9918AのMODE2(またはMODE0)では、4KBまたは16KBのVRAMの特定範囲にパターンテーブルに相当するパターンゼネレーターやネームテーブルなど(※その他にも色々なテーブルがありますが割愛)を配置することができ、更に単色のスプライトを表示することもできました。(スプライトについては後ほど詳述します)
(キャラクタパターン方式の盛衰)
キャラクタパターン方式がゲーム機のカテゴリで覇権を取った勝因としては、パイオニア的な存在だったTMS9918シリーズの存在が大きかったと思われますが、1983年に発売したファミリーコンピュータ(任天堂)の影響が更に大きかったように思われます。
ファミコンのVDPに相当するPPU; Picture Processing Unit「RP2C02」は、TMS9918とは全く異なるアーキテクチャですがキャラクタパターン方式にのみ特化しています。
RP2C02では、4色のカラフルなキャラクタパターンを表示でき、全方向のスムースなハードウェアスクロールができる2画面分の広大なネームテーブルを標準で使用することができ、更にカラフルなスプライト(透明色を含めて4色)を表示できました。
これらの特徴は1983年当時2年落ちのテクノロジーだったTMS9918Aの性能を圧倒的に凌駕しています。
ファミコンのPPUに関する詳細は以下の記事が詳しいかもしれません。
1985年に登場したセガマークIIIのVDP(315-5124)は、MODE4と呼ばれる新たな画面モードが追加されており、標準(マッパー0)のファミコンのハードウェア性能を上回ります。
315-5124については以下の記事が詳しいかもしれません。(※ゲームギアにはセガマークIIIのVDPとほぼ同じものが搭載されています)
1989年に発売されたセガマークIIIの次世代機「メガドライブ」、1990年に発売されたファミコンの次世代機「スーパーファミコン」でも、キャラクタパターン方式が更に強化されたVDPが搭載されました。
当時、永遠に続くかのように思われたキャラクタパターン方式の繁栄は、プレイステーションが登場する1994年末ごろに崩壊することになります。
奇しくも崩壊の足音が迫る1994年初頭、プログラマとしてのキャリアをスタートさせた私(※中学1年生)はPC-9801というパソコンしか持っておらず、まるでファミコンのようなグラフィックス表現が簡単にできるMSXやX68000等の投稿プログラム(※マイコンBASICマガジン掲載)のスクリーンショットを羨望の眼差しで眺めていたことを未だに覚えています。
なお、「持っている」という表現には若干語弊があり、正確にはパソコン部に入って学校のPC-9801を使って毎日のようにゲームを作って遊んでいました。
後に親がPC-9821(CanBee)を買ってくれたので、日夜を問わずプログラミング漬けの生活を送ることができたのですが、その時にはキャラクタパターン方式のコンピュータはほぼ幻想入りしていたため、終ぞキャラクタパターン方式でゲーム・プログラミングできる機会は無く、ずっと憧れの存在のまま今に至ります。
もちろん、エミュレータの技術が発達した昨今では、昔のハード向けのプログラムを簡単に書いて動かすことならできますが、少なくともキャラクタパターン方式を公式採用するフーリッシュな最新のゲーム機が登場することは常識では考えられません。
(キャラクタパターン方式の利点)
キャラクタパターン方式には、少ないユーザプログラムの処理量で多くの画面更新ができるメリットがあり、例えばネームテーブルを1バイト更新するだけで8x8ピクセル(64ピクセル)分のグラフィックスを一気に更新できることになります。
(キャラクタパターン方式の弱点)
キャラクタパターン方式には、VRAMのメモリ・レイアウトが複雑な構造(複数のテーブルを持つ形)になるデメリットがあり、その影響でディスプレイICチップの構造が複雑になってしまう(部品点数が多くなってしまう)ため、量産時にコスト面で不利になります。
そのため、近年のゲーム機(に限らずコンピュータ全般)のディスプレイICチップには高コストなキャラクタパターン方式は実装されず、シンプル&低コストなビットマップ方式(後述)のみ実装されているようです。
実際、東方VGS実機版が採用しているディスプレイICチップ(ILI9341)も、データシートを見る限りビットマップ方式しか実装されていません。
ただし、ユーザプログラムがシンプルになるメリットは有用なため、OSなどの基本ソフトウェアがキャラクタパターン方式のVDPをシミュレートした機能とインタフェース(API; Application Program Interface)を提供しているため、ユーザープログラムは printf 関数を実行するだけで簡単に Hello, World! という文字列を画面に表示することができます。
(2) ビットマップ方式
ビットマップ方式は、ビデオメモリ(VRAM)が画面の画素(ピクセル)に対応したメモリレイアウトになっている画面表示方式です。
この方式には、VRAMのレイアウトがシンプルになるメリットがある一方、キャラクタパターン方式と比べると画面更新に掛かるユーザプログラムの処理量(≒VRAM更新回数)が多くなるデメリットがあります。
前節で示したキャラクタパターン方式(1キャラクタ8x8ピクセル)では、1バイトのVRAM(ネームテーブル)の更新で64ピクセル分の画面表示を更新できましたが、1ピクセル1バイトのビットマップ方式のディスプレイICで同じ画面更新を行うには64バイトのVRAM(ビットマップ)の更新が必要になります。
なお、PC-8801のカラーグラフィックス画面はビットマップ方式ですが、横8ピクセルを1バイトとする1画面(640x200ピクセル)分のVRAMが色素(RGB)毎に3枚ある形(つまり、1ピクセル3ビット)になっているので、8x8ピクセルの矩形更新を行うのに必要なVRAMの更新サイズは24バイト(1バイト×縦8行×3VRAM)で、PC-98の16色モードでは更にもう1枚色素VRAMが追加されて1ピクセル4ビットなので32バイトの更新が必要です。
ビットマップ方式のメモリレイアウトは基本的にはシンプルですが、色が8の倍数ビット(バイト)単位でない場合、プログラムでの扱いがシンプルではなく面倒(複雑)になる傾向があります。
ILI9341のデータシートを見ると18ビットカラー(RGB666)が扱えるようですが、18ビットだとプログラムで扱いにくいため、赤(R)と青(B)の色素ビットを1ビットづつ削った16ビットカラー(RGB565)が主に使われています。
(3) ポリゴン方式
ポリゴンとは、座標に奥行き(Z座標)の概念を加えた三次元座標系(XYZ)の三角形を単数から複数描画することで、疑似3Dの映像を2D画面に表示するテクノロジーです。
一般的には三角形1つ=1ポリゴンという単位で表し、矩形(四角形)を表示するには2ポリゴン必要です。
ただし、セガサターンの場合はスプライト(矩形)を変形させてポリゴンを表現していたため、矩形1つ=1ポリゴンだと考えられますが、この方式は残念ながら一般化されなかったようです。(個人的にはサターン方式のポリゴンの方が直感的で扱いやすいと思います)
ポリゴンの表面に矩形の画像を貼り付けること(テクスチャマッピング)もできるため、2ポリゴン+テクスチャマッピングにより2Dのキャラクタパターンを表示することもでき、頂点座標を更新することで拡大縮小、回転、変形などを自由自在に行うことができます。
数千万〜数億といった膨大な数のポリゴンを用いることでリアルな疑似3D空間を再現できるメリットがある一方、とてつもなく膨大な量の計算が必要になるデメリットがあります。
ポリゴン方式には、このデメリットの影響で「描画性能」と「消費エネルギー」という2つの大きな課題があります。
ポリゴン方式の描画性能面の課題解決のため、表示に必要な計算(主に行列演算)を高速に行うことに特化したGPU; Graphics Processing Unitと呼ばれるICチップ(NVIDIAのGeForceシリーズ等)が進化することになりました。
GPUの進化は、一定の分野でスーパーコンピュータのフロップス(単位時間での浮動小数点数の計算量を示す性能指標)を引き上げることにも役立ち、主に膨大な量の行列演算を必要とする深層学習(ディープラーニング)と呼ばれる特徴抽出アルゴリズム(ChatGPTなどで使われているテクノロジー)の分野などに貢献しているようです。
しかし、膨大な量の計算を実行するには当然ながら多くのエネルギーが必要になるため、膨大な電力消費と冷却設備が必要になることで、極めて大きな環境負荷が掛かる課題があります。
もちろん、環境負荷の課題はGPUスパコンに限った話ではなく、シンプルに「たくさん計算するにはたくさんエネルギーが必要」ということで、その課題を解決する研究も盛んに行われているようです(参考)が、現状では富岳を1時間動作させるのに4人世帯家庭の消費電力の約75ヶ月分程度の電力が必要になる(参考)らしいです。
スパコンを触った経験がある人はかなり限られる(私も触ったことがない)ためイメージし難いのですが、スマホでゲームをプレイすると凄まじい勢いでバッテリー残量が減り、端末がホットカイロのように熱くなるアレ(が何万倍かのスケールになったもの?)みたいな感じだと思われます。
現代のコンピュータのチップセットには当然のようにGPUが搭載されるようになったため、ポリゴン方式が最もポピュラーなゲームのグラフィックス描画方式の地位を獲ったと言えるかもしれません。
ポリゴンの正確な理解には高度な数学知識が必要(≒学習コストが高い)という難点がありましたが、その課題は開発ツール(SDK; Software Development Kit)が克服しているようです。
かつて、Unityと呼ばれるSDKが流行っていた時期があり、Unityを用いれば3Dに関する数学知識がゼロの人でも簡単に3Dのゲームを作ることができました。(現在の主流はUnreal Engine?)
FlashやUnityなどのクローズドで不自由なSDKに依存するのはとてもリスキーなので、3Dゲームを創りたかったら必要な数学知識を習得してもっとオープンで自由なSDK(OpenGLとか?)を使うべき…
…などと、3Dのゲームに全く思い入れが無く、3Dプログラミングの習得を断固として拒否してきた私が偉そうに言っても説得力が無いかもしれません。(単純に3Dは酔うから嫌い)
「3Dなどいらぬと、3Dを極めてから言えホ…!」
と言われれば返す言葉もありません。
ポリゴン方式 = 排除
リリース当初の東方VGS実機版のSDK(vgssdk-pico)が提供するグラフィックス描画機能(VGS::GFX)は、ビットマップ方式のみで、キャラクタパターン方式とポリゴン方式を省略しています。
ポリゴン方式は意図的に省略(排除)しました。
ポリゴン方式に対応した方が創れるゲームの幅が広がるのは間違いないと思いますが、ポリゴンが無ければゲームが創れない訳ではないので不要かな?ということで。
もちろん、コスト面の都合という合理的な事情もあります。
ただし、ポリゴンへの情熱があれば合理性などガン無視して採用したと思うので、結局のところは好みの問題だと思われます。(そもそも、個人でゲーム機を創ろうという発想が非合理の塊ですし)
キャラクタパターン方式 = 採用
一方、キャラクタパターン方式のメリットは、処理性能が低いRP2040でゲームを開発する必要がある東方VGS実機版には必須だと考えられます。
ですが、何より私にはキャラクタパターン方式への情熱があるので、合理性云々に関係無くコレを外すことは不可能です。
ただし、そのために専用のICチップ(VDP; Video Display Processor)を追加することは(東方VGS実機版では)出来ないので、VDPをエミュレーションしたものをvgssdk-picoに搭載することにしました。
もちろん、専用ICチップを自前で作る方が(実用性はさておき)ロマンがあると思いますが、VGSは量産化されていて流通量が多い(安価に調達ができる)既成のICチップのみ使う方針です。
ですが一応、ASIC、FPGA、CPLDなどでICチップ化しやすい設計にしてみたつもりです。
私はそっち方面は完全に専門外なので、実際にICチップ化しやすいのかは定かではありませんが、過去に幾つかのゲーム機エミュレータを作ってみた時の知見を基礎に設計しているので「恐らく大丈夫かな?」と想像してます。
VGS::VDPの設計思想
VGS::VDPの設計思想はメガドライブのVDPに寄せてみたつもりです。
もちろん、完全に同じものにするのではなく、RP2040で適度なパフォーマンスと最適なソフトウェア生産性が得られるようにする観点でゼロから設計しました。(ARMのCPUが6502にインスパイアされて作られたという話をどこかで聞いたことがありますが、文脈としてはだいたいそれと同じだと思われます)
また、従来のビットマップ方式のグラフィックス機能(VGS::GFX)を置き換えるのではなく、それと共存した形でキャラクタパターン方式のVDPエミュレータ(VGS::VDP)を新設しています。
VGS::GFXはMSX2のコマンド(V9938の機能)に近いものがあるのでMSX2相当のパソコン的なグラフィック表現ができつつ、VGS::VDPでメガドライブのようなゲーム的なグラフィック表現も可能…という何とも奇妙なゲーム機になりました。
本当は画面いっぱいのサイズ(240x320ピクセル)でVGS::VDPの画面を表示できるようにしたかったのですが、ハードウェアの制約(RP2040の処理性能とメモリサイズの制約)の関係で、最大でも192x240ピクセル(下図赤枠の範囲)で20fps程度の性能が限界でした。
なお、VGS::VDPの仕様自体かなりフレキシブルな設計にしておいたので、もっと高性能なSoCを使えば全画面で表示したり60fpsにすることも可能です。(VGS-Zeroの布石)
ゲームのメイン画面(動的な部分)はVGS::VDPで描画しつつ、スコア表示やステータス情報など(ほぼ静的な部分)はVGS::GFXで描画するような使い方を想定しています。
VGS::VDPのVRAM
VGS::VDPのVRAMには、先述の「(1) キャラクタパターン方式」で解説したパターンテーブル(ptn)とネームテーブル(bg)の他に、scrollX、scrollY、oamという謎の領域があります。
見る人が見れば全然謎ではない(名前だけで機能がイメージできるもの)と思われますが。
スクロール(scrollX, scrollY)
VGS::VDPの画面サイズは、先述の通り最大192x240ピクセル(幅×高さ×2≦90KB)という仕様ですが、ネームテーブルはピクセル換算すると512x512ピクセルです。
つまり、ネームテーブルが表示画面の上限よりもかなり広大なサイズになっていますが、これは設計ミスではありません。
scrollXとscrollYでネームテーブル上の描画開始基点を指定できます。
例えば、scrollX・scrollYの加算・減算とレンダリングをループさせることで8方向のスムースなスクロールをすることが可能です。
また、範囲外座標の描画はループする仕様です。
これは、典型的なゲーム機に搭載されているVDP(ファミコンのPPU、スーパーファミコンのS-PPU、セガマークIIIのMODE4、メガドライブのMODE5など)に搭載されているハードウェアスクロール機能とほぼ同じ仕様です。
ただし、スプライトの描画処理を単純化(高速化)したかった関係でH-SYNC割り込み(特定のスキャンライン位置で発生させる割り込み)をサポートしていないため、ラスタスクロールを活用した疑似3Dレーシングゲーム等の実装はVGS::VDPでは困難かもしれません。
スプライト(oam)
OAM(Object Attribute Memory)とは、スプライトのレコード情報を格納する構造体で、VGS::VDPのOAMには座標(X, Y)、パターン番号、ユーザ情報の3種類の属性があります。
スプライトとは、任意のキャラクタパターン(※VGS::VDPの場合はBGのキャラクタパターンと共用)を任意の座標へ動的に表示できる機能で、主にゲームのキャラクタ描画に使われます。
VGS::VDPが提供するスプライト機能は、典型的なゲーム機が提供するスプライト機能と概ね同じ仕様です。
典型的なゲーム機のスプライト機能との違い
表示属性
スーパーファミコンやメガCDのスプライトには拡大縮小、回転、半透明などの機能があるのに対し、VGS::VDPのスプライトにはそれらがありません。(メガドライブのスプライト相当)
典型的なゲーム機のVDPでは表示属性でvisible/hiddenを指定する仕様になっていますが、VGS::VDPの場合はパターン番号に0(0x00)を指定すると非表示(パターン番号0はスプライトとして利用不可)という仕様になっています。
水平上限
典型的なゲーム機のVDPのスプライト機能には水平上限というハードウェア上の制約があり、ファミコンならスキャンライン毎(水平方向)に最大8枚(※スーパーファミコンなら32枚、メガドライブなら20枚)までしかスプライトが描画できず、水平上限を超える優先度が低いスプライトは描画が省略される特徴があります。
VGS::VDPのスプライトには水平上限が無い(※無い方が高速に描画できる)ため、256個並べて描画してもチラつきません。
色数
キャラクタパターンに指定できる色数は透明色を含めて最大65,536色(スーパーファミコンやメガドライブはパレット方式で、1枚のキャラクタパターンに使用できる色数は透明色を含めて最大16色)です。
個人的には16色使えれば十分だと思っているのですが、パレット方式(16色)よりもハイカラー方式(RGB565)の方が描画処理を高速化できるため、ハイカラー方式を採用しました。
VGS::VDPの場合、スプライトの色に0(0x0000)を指定した部分が透明色になります。
上記以外の特徴として、OAMレコードにユーザープログラムで自由に使える3バイトのユーザ情報(user)という領域を持っています。(※セガマークIIIやゲームギアのOAMにも似たような領域があります)
これは、RP2040が32bit CPU且つ厳密な4バイトアライメント構造なので、数値型は4バイトで持たせるのが最も処理効率が良く、その関係で頻繁な計算処理が必要な座標変数を4バイト整数(int)にしていますが、パターン番号は(冗長なレンジチェックを不要にする為)符号なしの1バイト整数にしているため、3バイト分のバウンダリ領域(冗長領域)が発生することになり、折角だからその領域をユーザプログラムが自由に使える変数領域として明文化してみた形です。
たった1バイトでもOAMにこういった冗長領域があるだけで助かる場面が多々あります。(実際にファミコンでゲームを創ってみた時に欲しいと感じたので入れてみました)
もちろん、何メガバイトもの広大なRAMが自由に使える昨今のSoCでは不要な配慮ですが、RP2040が扱えるRAMは264KBしかない(かつ、その半分以上をVGS SDKが専有している)ため、こういったメモリを節約できる配慮は必須だと考えています。
スプライト機能の定義
VGS::GFXが内部的に利用しているTFT_eSPIにも「TFT_eSprite」と呼ばれる機能があり、TFT_eSPIのラッパークラスであるVGS::GFXにも同じ機能があるのですが、VGS::VDPのスプライト機能との混同を避けるため、VGS::GFXではこの機能のことを仮想ディスプレイ機能(virtualDisplay)と呼んでいます。
そもそも、スプライト(直訳すると妖精)とは、1978年にアタリ社により考案されたものが基礎になっています。
私は様々なゲーム機が搭載しているスプライト機能を見てきた結果、スプライトの機能要件を次のように定義しました。
TFT_eSpriteは私が定義するスプライトの機能定義に合致しませんが、仮想ディスプレイ機能としてはとても有用なので、名前を変えて残すことにしました。
何故、TFT_eSPIの作者さんがこの仮想ディスプレイ機能を「スプライト」と呼ぶことにしたのか…という点がとても興味深いです。もしかすると、現代におけるスプライト機能の一般定義が変化しているのかもしれません。
そして、レトロなゲーム機ばかり研究している私が時代遅れな筈orz
C/C++でゴリゴリ扱えるVDP
VGS::VDPはC/C++で処理を記述する前提の仕様になっていますが、C/C++でVDP処理が簡潔に記述できるという点がメリットとして大きいかもしれません。
これには、ゲーム機の歴史的な事情が関係します。
昨今のゲーム機にはLLVMが搭載されていると思われる(搭載しない理由が無いと思われる)ので、C/C++に限らずRust等の様々なプログラム言語でプログラムを記述できるものと思われます。
しかし、キャラクタパターン方式のVDPが全盛期だった頃のゲーム機(スーパーファミコンやメガドライブ)は、処理性能的な事情でまだオールマシン語(アセンブリ言語のみ)でのゲーム・プログラミングが主流だったと考えられます。
そして、その次世代ゲーム機に当たるプレイステーション(1994年)以降、ゲーム機の画面描画はポリゴン方式が主流になり、キャラクタパターン方式のVDPは廃れました。
ちなみに、プレイステーション(ポリゴン方式)世代あたりからは流石にC言語が使われていただろう…と安直に思っていた時期もあるのですが、セガサターン版「ナイツ」をプレイステーション2に移植したことを記した記事にセガサターン版ナイツはオールマシン語で作られていた旨が語られています。(SH-2はRISCなのにフルアセで組めるのか😅)
そのような背景事情から、高級言語(C/C++)でキャラクタパターン方式のVDPを扱う家庭用ゲーム機向けプログラムを記述した経験があるゲームプログラマは少なかったものと考えられます。
もちろん、X68000辺りならC/C++で記述することも出来たかもしれませんが、CISCアーキテクチャであるMC68000のマシン語は高級言語並に扱いやすいこともあり、特に性能が求められる場面が多いVDP関連の処理はマシン語で記述するのが主流だったと考えられます。
また、同様にMSXにもC言語がありましたが、MSXのCPU「Z80」は息が長かったこともあって技術書が本屋に豊富にあったことに加え、Cコンパイラは数万円程度する高級品だったので、「初心者はBASIC」「上級者はマシン語」という極端な二極化をしていたのではないかと考えられます。
つまり、キャラクタパターン方式(&スプライトあり)のVDPの制御処理をC/C++でゴリゴリ記述するプログラミングスタイルは、キャラクタパターン方式を知らない若い現役世代のゲームプログラマだけでなく、キャラクタパターン方式を懐かしむロートルなゲームプログラマにとっても新鮮かもしれません。
私はZ80がそこそこ得意(自作のエミュレータを作れる程度)なので、Z80のオールマシン語でゲームのプログラムを書くことも一応できますが、それでもやはりC/C++の方がプログラミングし易い(生産性が高い)と思っています。(マシン語プログラミングにはマシン語プログラミングの良さや面白さがあるので、生産性の話を抜きにすればオールマシン語でのプログラミングもオススメしたいところではありますが)
最近のイケてるナウいゲームプログラマならRustかもしれませんが、RP2040の性能だとLLVMバックエンドを動かすには性能的に少々キツイかなと。
RP2040が公式にサポートしているプログラム言語はC/C++ or μPythonとのことなので、RP2040でゲームプログラミングをするなら事実上C/C++一択だと思われます。
IoT用途ならμPythonの方がサンプルが多くて良いかもしれませんが、VGS; Video Game SystemはIoT機ではなくゲームを創るためのシステムなので、SDKはC/C++のみです。
2. 効果音の再生
約8年前(2015年10月ごろ)の私曰く、
とのことです…なるほど?🤔
長年ブログを書き続けていると、かのような怪文書が残り続ける場合もあり、とても愉快な気分になれるのでオススメです。(黒歴史もまた歴史)
最近の流行りはブログではなくYouTubeでVLOG(動画ログ)かもしれませんが、動画よりもテキストの方が短時間で読み返せて検索も簡単なので、記録目的なら動画化よりも文章化がオススメです。
他にもYahooブログ、ニコニコのブロマガ、Google+など、現在ではサービス終了している数多のテキスト系クラウド・プラットフォームで様々な怪文書を投稿してきましたが、残念ながらそれらの大半を見ることはもう出来ません…やったぜ☆
全てのクラウドサービスは水蒸気の塊に過ぎないので、将来的に全て霧散する前提で使っています。本当に残したければWordPressなりで自分用のサーバを建てるべきですが、怪文書投稿家曰く「消えるから美しい」とのことで雲役務を好んで使っています。
Bloggerは、あのR.I.P.メーカーことGoogle運営なのに未だに続いています。テキストベースだからランニングコストが安い割にAdSense広告との相性も良いということなのかもしれません。(知らんけど)
余談はさておき、ゲームにおける効果音は物凄く重要で、仮にBGMが無くても「効果音さえ適切に鳴っていればゲームっぽい雰囲気は成立する」と今でも思っています。
なので、ゲーム開発する時に「BGM or 効果音」の究極の二択を迫られた場合、やはり効果音を取ります…と、東方VGS(BGMのみ&効果音無し)しかヒット作が無い私が言っても説得力が無い気がしないでもないです。
「BGMなどいらぬと、BGMが無いゲームをヒットさせてから言えホ…!」
という訳で、本題の効果音機能を付けました。
VGSの場合、波形メモリ音源(VGS::BGM)は音楽の再生専用で、効果音再生は22050Hz, 16bits, モノラルの任意PCM形式で再生する仕様(これは初期のVGSの頃から同じ仕様)です。
処理性能の関係で複数の効果音を同時再生(合成再生)することはできず、効果音1を再生中に効果音2を再生すると効果音1の再生がキャンセルされて効果音2の再生が始まる形になります。
3. ゲームパッド(WIP)
ゲームパッドの対応については、部品集めの段階なのでまだできていません。