ゲームとVM
Another World(アウターワールド)の解析が載っている。興味深い。
国内ではソーサリアンの解析が有名な気がするが:
最近のネタだと洞窟物語のVMだろう( http://nxengine.sourceforge.net/ )。(WikipediaにはGame engine recreationというページまで有る http://en.wikipedia.org/wiki/Game_engine_recreation )
ゲームをVMで実現するという発想自体は、コンピュータゲームがその黎明期からBASICのようなインタプリタで書かれていたことを考えれば至極普通のことで、少なくともMSのBASICは中間表現としてのバイトコードをかなり早期からもっていた。(ただ、TinyBASICの類は直接ASCII形式のソースコードの文字を引く実装であることが多い。例えばDDSBASICのように - http://cis.csuohio.edu/~somos/ddsbasic.c )
ただ、BASIC自体の動作制約やゲームプラットフォームの拡大があったので、In-houseのVMというかたちでかなり多くのVMがデザイン/実装された。
↑のiv以外にも、LucasArtsのSCUMMや日本におけるほとんどのギャルゲー(!)がVMベースで実装され、多くのギャルゲーベンダは自前のスクリプトエンジンとしてVMとその記述言語を持っていた(ビジュアルアーツのVAO game*1やAliceSoftのSystem等)。
Another Worldでは、開発環境に関する制約がほぼ見られない。同時期(〜1990年付近の)マイコンやDOSゲームの多くはプログラムをモジュール化するなど開発環境とゲーム自体を同居させるための工夫を払っているゲームも多い。しかし、Another Worldの開発自体はPCよりもリッチなAmigaで行われた( http://www.4gamer.net/games/113/G011302/20110305006/ )ため、ゲーム自体にはそのような痕跡が無いように見える。
ゲームにおけるVMの採用はSCUMMのようなアドベンチャーゲームでの採用が有名なので、VMは非リアルタイムなゲームで使用されているというイメージがあるかもしれない。しかし、近代的なゲームのほとんどはいわゆるVMをリアルタイムなゲームにも使っている。
洞窟物語や多くの"ゲームエンジン製のゲーム"は、ゲーム内物理やアクション部分をハードコードし、オブジェクトに触れた際のイベント等をスクリプトに追い出している。シナリオ等の調整を、プログラム本体を修正することなく行えるようにする配慮といえる。
レジスタとマルチスレッド
Another Worldを含め、非常に多くのVMは"レジスタベース"つまり、高速にアクセスできる、それなりの大きさの静的に割り当てられた配列を持っているように思える。VMコードを書くプログラマがそれらの役割を静的に配置して使用する(レジスタ5は表示中のステージ番号を表す 等)。
このようなデザインは、TinyBASICやそれに似たGAME等VTL系の言語のように変数名に対するストレージが静的に割り当てられていた時代背景を考えれば自然かもしれない。ただ、"ストレージの管理機構を持つか"はこの手のゲームVMをクラス分けする点として有用に思える。
初期のRPGツクールや↑のソーサリアンではレジスタにはフラグしか格納できない(= 1bit長しかない)。
Javaや.net(CLI)のVMはスタックベースのVMだが、この時代のゲームは限られたリソースで動作する必要から消費リソースを厳密に規定するため、可能な限り決定的(deterministic)な手法を好む傾向にある。もちろんスタックベースのVMでも使用されるスタックの量を予測することは不可能ではないが、レジスタベースのVMの方が"レジスタ割り当て"の形でより簡単にリソース消費を規定出来る。
この時代のVMもマルチスレッド/マルチタスクをサポートすることが多い。ゲームは同時に多数のキャラクタが動きまわるのが普通なため、キャラクタ毎に別々のプログラムを与えて同時に動作させたいというのは普通の要求と言える。多くのVMはプリエンプティブではなく、Another Worldのように単純にプログラムカウンタ(と、場合によってはレジスタ)をコンテキストとして持つ。
スレッドの数や役割は、ぐるみん(FALCOM)のように固定されている(キャラクタ動作/シナリオイベントの2つ)ケースもあるが、近代的なゲームではUnchartedやその他ゲームエンジン製のゲームのようにキャラクタ/イベントストリーム毎に固有のスレッドを動的に持てることが多い。
Uncharted 2はスレッドとそこに供給されるイベントをTrackという形に抽象化し、個々のスレッドは(Scheme的な意味の)継続で管理される。
VMの将来
しかし、このようなゲーム固有のVMを使用する時代も終わってきていて:
とにかくこの業界ではLuaが強い。SCUMMもLuaに移行している。
Luaが強い理由は非常に単純明快で、ライセンスがpermissiveで、.cのソースコードをいくつかリンクすればすぐにつかえるという手軽さにある。
どちらにせよ、独自のDSLをゲーム向けに書くというのはあまり良いアプローチでなくなってきた。独自の言語を採用するのは、プログラマの単価を上げてしまう可能性がある。
- その他の組み込み言語: GameMonkey, Squirrel, ECMAScript, ...
ここで取り上げたものだと、GameMonkeyはPixelJunkシリーズ(PS3)、Squirrelはひゅ〜ストン(Nintendo 3DS)に採用されている。
SchemeもminischemeやTinySchemeのように非常に少ないソースコードですぐ実装できるものが有るので、ゲーム向けのものをきちんとつくれば入り込む余地はあるように思える。特に、良いIn-Gameエディタ/デバッガ/ビジュアライザを備え、少ないソースで導入できる実装は現状どのような言語であっても存在しない。
家庭用ゲーム機や携帯電話では、実行時のコード生成(JITC)が禁止されているケースが多いので、静的なコンパイラに需要がある。また、UnrealScriptなどは、スクリプトでオブジェクトを定義してその定義をヘッダに書き出すなどC++との統合がそれなりに意識されている。
僕個人はこの方式をよく使っていたが、現代的にはあまり使われていないように思える。ただ、今後この方式はそれなりに伸びると思っていて、Mandreel( http://www.mandreel.com/ )のようなJavaScriptへの変換やGPUプログラムの生成(GLSL vs. HLSL, OpenCL vs. C++ AMP)などの分野が考えられる。(Mandreelに至っては手書きのJavaScriptより速いケースもある - http://blog.j15r.com/2011/12/for-those-unfamiliar-with-it-box2d-is.html )
そして、このような分野だとDSLが生き残る可能性も十分にある。