土屋つかさの技術ブログは今か無しか

土屋つかさが主にプログラミングについて語るブログです。

ゲームプログラミングの新手法「コード注入式ステートマシン」の可能性を探る(意図的な煽りタイトル)

 Ruby Game Developing Advent Calendar 2016(http://www.adventar.org/calendars/1647)の16日目です。15日目はあおいたくさんの「なにか」でした(なにか!)。

懲りずにオリジナルのメッセージ指向ゲーム開発言語「司エンジン」の紹介

・……が、当初予定していた記事だったのですが、これについては、別の記事で書いたので是非そちらをどうぞです。

オリジナルのメッセージ指向ゲーム開発言語「司エンジン」でジャンプアクションゲームを作ってみる
http://d.hatena.ne.jp/t_tutiya/20161201/1480604440

・今回の記事ではもうすこし突っ込んだ司エンジンのの特徴について書いてみたいと思います。

コード注入式ステートマシン(code injection state machine)

・司エンジンの特徴の一つに「ステートマシンを動的に定義できる」というのがあるのですが、どうもこの説明だと「ディスパッチパターンなどで任意のステートマシンを動的に生成できる」とか「コードジェネレーションなどで任意のステートマシンの実装を動的に生成できる」とかではないということが、上手く伝わらないようだと分かってきました。

・より具体的に書くと「既に生成されているステートマシンの実装をリアルタイムに変更出来る」という方が近いでしょうか。仮にこれを「コード注入式ステートマシン(code injection state machine)」と呼ぶ事にしましょう。「コードインジェクション」はハッキングの手法の一つですが、原理的には司エンジンのメカニズムはこれになります。

・司エンジンではステートマシンの「ステート」に相当するコードを、ツリー上位の親ステートマシンから「注入」されることで内部に保持します。複数のコードが注入されるとそれらはキューにスタックされ、順番に実行されます。また、実装されたコードはキューから削除されます。キューが空になったステートマシンは、再び親ステートマシンからのコード注入を待機します。

・ゲームプログラミングでは、ステートマシンが取り得るステートの種類や、次に実行するステートを判別するロジックが複雑になる傾向があり、これがコーディング時の作業負荷に直結します。司エンジンでは、その部分を柔軟に編集できるようにして、その負荷を軽減させています(なにせ実装をリアルタイムに編集可能なのです!)。

サンプル

・サンプルを作ろうと思ったのですが、細かいバグをピンポイントで踏んでしまい、短く分かりやすいサンプルになりませんでした(ごめんなさい)。バグ修正後に新しいサンプルを作りたいと思っています。

・動作デモ動画はこちらになります。
https://youtu.be/TVfPfCHGZRQ

・左上のボタンを押すと、対応する方向に回転する四角形(Imageコントロール)が移動します。ボタンを連続してクリックすると、順番にその方向へ移動します。

・背後のコマンドプロンプトで、押したボタンに応じて、Imageコントロールのキューに注入されているコードが表示されています。1方向の移動が終わるたびに、コードの行が減っているのが分かるかと思います。

・ボタンのコードはこうなっています。

_TEXT_BUTTON_ text: "",  out_color: [0,255,255], #カーソルがボタン外にある時の背景色
  in_color: [255,255,0] do
  #キーがクリックされた
  _DEFINE_ :on_key_push do
    _SEND_ [:bg] do
      _SET_ bgcolor: [255,0,0]
    end    
    _SEND_ [:_ROOT_, :target] do
      _PUTS_ "*************************************"
      _DEBUG_COMMAND_
      _GET_ [:x, :y] do |x:, y:|
        _MOVE_ [120, :out_quart], x:[x, x + 60]
      end
    end
  end
end

・この中で"_SEND_"の中に記されているのが、このボタンを押すことによってImageコントロールに注入されているコード群になります。ここではコマンドプロントに文字列を表示したのち、_MOVE_コマンドで自分自身を移動させています。

・それぞれの移動がボタン押下のタイミングと非同期に行われていることから分かるように、これらのコードはボタンが押された直後に実行されているわけではなく、いったんImageコントロールに注入された後、既に注入されていたコード群が実行された後に、初めて実行されるのです。

終わりに

・うーん、自分で書いててもわかりにくいな……。バグを直してもう少しわかりやすいサンプルコードを作るので、暫くお待ち下さい。

・今回のサンプルコードは以下になります(v2.1で動作確認。v2.1はクリスマスにリリース予定だけど、どうだろう、間に合うのかな……)
https://gist.github.com/t-tutiya/584a1ea1b1b06cc56fcecdaf0d2c712d

・明日はしのかろさんです。