頼りないニモニック

はっきりいって個人の日記レベル

ゲームライブラリを作っています

ux をどうにか活かしたいという思惑と、とある事情で自由な成果物を制作する機会があるため、2Dゲームライブラリを制作しています。Sitrine (シトリン)という名称で、由来は黄水晶を意味する citrine です。ちなみに 黄水晶 は 11月の誕生石です。

当初は「ゲームエンジン」と名乗っていたのですが、補助的な役割が適切と考え「ゲームライブラリ」と今では名乗っています。その構想と現状をここに書き留めておきます。

OpenTK の補助ライブラリとして

Sitrine は OpenTK を利用します。OpenTK は OpenGLOpenAL、OpenCL などを C# で使えるようにしたライブラリです。OpenTK 自体の更新は Github 等で続けられていて、非常に優秀なライブラリが揃っています。無論 Mono と併用できますし、C#クロスプラットフォームなアプリケーションを制作できます。

Sitrine の一つ目の顔、それはその OpenTK にさらに使いやすく(自分仕様に)してしまおうという補助ライブラリの面です。OpenGL のいくらかの処理はクラス化して利用した方が簡潔です。具体的にはビットマップの操作、フォント、文字列などのクラス群をすでに実装しました。自身の技量もあり 3D ゲームライブラリは敷居が高すぎるため、あえて 2D に限定しています。

ux の活用として

ux はそもそも、Xylph をさらに軽量化してゲーム(など)に応用しようという目標で作られました。Sitrine は ux を利用するようになっています。現状では ux のみが音の出せる唯一の手段です。今後は MP3 などの PCM 音源を鳴らせるといいかもしれないですね。(もっとも、クロスプラットフォームで優秀なデコードライブラリがあればの話ですが...)

ストーリーボード

Storyboard とは日本語で絵コンテの意で、要するにシナリオなどを書いた筋書きのようなものです。ほとんどのゲームではシナリオがあります。このシナリオとは、オープニングからエンディングまでのキャラクタの行動という意味でもありますし、まさに絵コンテのようなどの場面はどういう動作をしてどうなるという意味でもあります。どんなゲームにもそういった意味でのシナリオは最低限存在します。

ところがこのシナリオをコーディングすると、若干複雑になります。

そもそもの話

例えばメッセージとして文字列を画面に表示したいと考えます。文字列をビットマップに描画し、それをテクスチャマッピングでポリゴンに貼り付けるという手法をとったとします。無事に画面が描画され、文字列が画面に表示したと考えます。入力を待ち、さらに後続の文字列を表示していくと考えます。残念なことに、文字列を表示し続けるような処理も全て自分でコーディングしなくてはなりません。(私が知っている) GUI アプリケーションにはこのような心配はまず必要ありません。

これをフローとして簡単に記述すると以下のようになります。

  1. 文字列を描画する
  2. ポリゴンを表示する
  3. 画面を描画する
  4. 入力がなければ 2. へ戻る
  5. 次の文字列を描画する
  6. ポリゴンを表示する
  7. 画面を描画する
  8. 入力がなければ 6. へ戻る...(以下略)

さて、OpenGL のプログラムを書いた方ならお気づきでしょうが、上記のフローは実は効率の良いものではありません。文字列が表示されている間もゲームの時間は経過しますし、音楽も鳴っています。これを考慮してフローを書くならば、

  1. 入力、計算、音楽の処理
  2. 画面をクリア
  3. 描画処理
  4. 描画開始
  5. 1 フレームの処理終了、若干待って最初に戻る

となります。

ではどうやってシナリオを書くのか?

さて、上記のフローを見た時、あなたはどうやってメッセージを表示させるでしょうか? 無論、プレイヤーがメッセージを読み取れるようにプレイヤーからの入力も待つ必要があります。私はそのフローをここに書きたくありません。なぜなら、それを書いてもシナリオ以外に書かねばならない処理が多すぎて実装する気にならないからです。その原因はずばり、ゲームのシナリオと内部処理が複雑に絡まっているからです。もしこれを、以下のようなフローで記述できれば、劇的に見通しが良くなるはずです。

  1. 最初のメッセージを表示
  2. 次のメッセージを表示
  3. ...

この場合、ゲームのシナリオ、つまり絵コンテの状態になりました。雑多な処理、すなわち描画だとか音楽の逐次処理だとかは全てなくなりました。こんなふうに書けるゲームライブラリが欲しいと私は思ったのです。

そしてできたのがこちら

その結果、今日のコミットで絵コンテ、ストーリーボードの実装がだいたい完了しました。上記のフローならば単純に、

Message.Show("最初のメッセージです");
Message.Show("次のメッセージです");

と記述して終了です。RPGツクールシリーズのイベント処理と同じ感覚です。メッセージとメッセージの間の入力処理もすべて自動でやってくれます。実はこの記述、実行時はそのとき実行せず、本当に実行されるその時のためにスケジューリングされます。早い話が遅延実行です。LINQ のように、本当に必要なときに初めて実行されるようになっています(正確には LINQ は実行ではなく 評価)。

つまり、普通の処理は即時実行されます。Sitrine が用意したメソッドに関してのみ、遅延実行されるのです。

Message.Show("最初のメッセージです");  // 遅延実行
Message.Show("次のメッセージです");  // 遅延実行
Console.WriteLine("hogehoge")  // 即時実行
int i = 42;  // もちろん即時実行
Message.Show("最後のメッセージです: " + i);  // 遅延実行

ところでこのストーリーボード、一度に並行して実行することも可能なように実装されています。主人公の会話がメッセージで表示されつつ、同時に敵が動きまわるようなストーリーボードも書けます。

メリット・デメリット

メリットとしては、書いたことがそのままシナリオになります。本来必要な入力処理もテクスチャの破棄作業も一切記述不要です。ゲームのまさに絵コンテのように記述できます。加えて、文字列処理などの複雑な処理をカプセル化(隠蔽)し、利用側は簡潔に記述できます。現在のコミットでは Message.Show メソッドしかありませんが、今後様々な処理を考えています。

デメリットとしては、実行処理そのものを遅延実行させるためメモリ効率が非常に悪いです。本来の即時実行と比べて、予め実行内容(加えてパラメータなど)をキューイングしますから当然の結果です。ただ、RPGツクールユーザとして、ほとんどのイベント数は長くても 100 くらいという経験則もあります。1万行分の処理は流石に難がありますが、その場合はストーリーボード自体を分割することも考えられます。


長くなりましたが、最後のストーリーボードが目玉です。まだまだ検討すべき事項が多くあります。それでも、中身がどういう実装になっているのかと興味がありましたら、どうぞ覗いていってください → https://github.com/nanase/sitrine