2006年03月30日

EJBとエロゲーと進歩

 EJBのことをさんざんけなしている私だが、徹底的に間違っているとは思わない(Berkeley DBは徹底的に間違っている)。気持ちはわかるのだ。私自身、EJBと似たようなことをしている。
 ビジュアルノベルのように、シナリオに沿って進行するタイプのゲームでは、状態管理が問題になる。どういう問題か、以下に一例を示そう。

 シナリオAの最後で選択肢が登場して、BとCに分岐し、さらにBの終わりではCに飛ぶものとする。つまり、シナリオの流れは以下の2パターンがある。
・A→B→C
・A→C
 さて、シナリオCはどちらの流れでも同じ内容なのだから、同じ状態を表現しなければならない。状態とは、画面表示やBGMなどだ。
 シナリオデータを作成する際は、基本的に、状態の変化を記述してゆく。「背景を××に変える」「BGMを××にする」という具合だ。すべての地点の状態を、シナリオデータに書き込んでゆくことはできない。そんなことをしたら、シナリオデータは以下のようになってしまうだろう。
 
----------------------------------------------------------------------------
[背景は××][BGMは××][立ち絵のキャラはS][Sの服装は××][Sの表情は××]
さて、これは。
----------------------------------------------------------------------------
[背景は××][BGMは××][立ち絵のキャラはS][Sの服装は××][Sの表情は××]
さて、これは。
いったいどういうことなのか?
----------------------------------------------------------------------------
[背景は××][BGMは××][立ち絵のキャラはS][Sの服装は××][Sの表情は○○]
私は考えた。
----------------------------------------------------------------------------
[背景は××][BGMは××][立ち絵のキャラはS][Sの服装は××][Sの表情は○○]
私は考えた。
こんなデータを人間が作れるのか?
----------------------------------------------------------------------------
 
 変化だけを記せば、以下のように自然な記述になる。
 
[背景は××][BGMは××][立ち絵のキャラはS][Sの服装は××][Sの表情は××]
さて、これは。■
いったいどういうことなのか?■
[改ページ]
[Sの表情は○○]
私は考えた。■
こんなデータを人間が作れるのか?■
 
 実際問題として、シナリオデータは変化だけを記すしかない。
 変化だけを記していく場合、シナリオデータがある地点で表現する状態は、その直前の状態に影響される。上の例でいえば、最初の行で指定された状態が、最後まで影響している。もし最初の行で、[背景は○○]と指定されていれば、最後まで背景は○○のままだ。
 全シナリオが最初から最後まで一本道につながっているのなら、これは問題にならない。だが、「A→B→C」と「A→C」の2パターンの流れを記述した場合、シナリオCの開始時点では、その直前の状態は2種類あることになる。
 さて、ここで大きな問題にぶちあたる。2つの考え方があるのだ。
 
逐次的:シナリオCが、その開始直前の状態に影響されることを認め、シナリオCが2種類の状態を表現することを許す
宣言的:開始直前の状態からの影響を排除し、シナリオCが表現する状態は常に1種類であると定める
 
 前者は、シナリオデータをプログラムとみなすものといえる。プログラムなら、たとえばループ内のループ変数のように、同じ地点が複数の状態を表現する。
 この方式は、プログラマには、自明のことに見える。私の知るかぎり、既存のビジュアルノベルフレームワークはすべてこの方式である。利点は、後者にくらべて表現力が高いことだ。たとえば、同じシナリオに違う背景をあてたい場合、逐次的データなら簡単に書ける。宣言的データでは、使いたい背景の数だけシナリオデータを作るしかない。
 だが現実には、逐次的データの表現力が生かされることはめったになく、害ばかりがある。害、すなわち、状態管理のトラブルだ。現実には、シナリオCに2種類の状態を表現させることはまずない。あるのは、意図せず間違って表現させてしまった場合、つまり、バグだ。
 
 宣言的にやる場合、開始直前の状態からの影響を排除するといっても、具体的にはシナリオデータにはどう書くのか。
 シナリオの開始地点となる場所で、[背景は××][BGMは××][立ち絵のキャラはS][Sの服装は××][Sの表情は××]という具合に、すべての状態を指定させるのか。だがこれは、最初に示した冗長な例ほどではないにしても、面倒くさすぎて現実的ではない。
 そこで私は考えた。
 A・B・Cとシナリオが並んでいるとき、再生順を無視してA→B→Cと頭から順に読んでゆけば、すべての地点で状態が一意に定まる。こうして得られた状態を、シナリオの流れがA→Cとなったときにも保つ。つまり、状態の変化だけが記してあるシナリオデータを、最初に示した冗長な例のようなデータへと変換して、これを再生する。(もちろん現実にはこんな馬鹿正直な実装ではなく、もっと効率のよい方法を採っている)
 
 おわかりだろうか。EJBではリソースやトランザクションをコンテナが管理するように、宣言的データでは状態をフレームワークが管理するわけだ。
 宣言的データはバグを減らすが、代償は小さくない。まず、管理下に置く状態を、かなり面倒なやりかたで宣言しなければならない。一時変数のようにアドホックに追加することはできない。一般にプログラマは万能チューリング機械に慣れており、有限状態機械は不自然で不便に見える。また現実には、管理されない状態も必要になる。いわゆる「フラグ」だ。すべての状態を宣言的に扱えるわけではないので、バグの可能性は常に残る。
 (C言語のincludeマクロのような表現と相対ジャンプを駆使すれば、フラグを管理下に置くことも可能だが、このような実装はまだ試していないので、その当否については保留する)
 シナリオデータ作成者は、考えること(状態管理)が減るかわりに、フレームワークを理解するための手間が増える。フレームワークを管理するのも、逐次的データのほうが楽だ。
 というわけで、宣言的データはまったくもって、EJBのコンテナ管理そっくりの様相を呈している。
 
 ソフトウェアはよどんでいる。コンテナ管理的なものへの試みや、有限状態機械の積極的な利用、つまり万能チューリング機械への挑戦は、どこにあるのだろう。私はEJBをけなすが、それはEJBがこうした問題に挑んでいるからだ。EJBの解答はろくでもないが、もし問題がくだらなければ、解答をけなすのは時間の無駄だ。
 アラビア数字が算数を簡単にしたように、なにか物事をまとめて簡単にする方法があるはずだと、私は信じている。EJBは問題をあまりにも狭い範囲に限定してしまったが、もっと広い範囲の問題を、もっと一般的に解けるはずだと、私は信じている。
 もし本当によい解答が見つかれば、それはソフトウェア産業の全面を変えるかもしれない。なにしろ、エロゲーでさえ、そうした解答を求めているのだ。

Posted by hajime at 2006年03月30日 20:56
Comments