前回は簡単な使い方について書いてみましたが、今回はどちらかというと考察が主になります。
スクリプトエンジンであるLuaですが、これをADV内部のスクリプトエンジンとして使ってみよう、と言うところですが、
そのときに関わってくるLuaの特徴から使用するときの考え方をとっていきます。
Luaはそれぞれの実行環境が完全に独立している
前回のコードで登場したLuaの状態管理構造体であるlua_State構造体ですが、これは各実行環境ごとに独立しています。
つまり、スクリプトを並列実行させるときはこのlua_State構造体を複数作成してそれぞれで実行させる、と言う行動をとります。
これの利点は
・環境が完全に独立しているため、真の並列実行も可能であり、OSのスレッド機能をフルに使うことが出来る
(システム管理部とシナリオ実行部と演出部を完全に独立して処理が可能。口パクの演出がやりやすい)
・並行実行の場合でもそれぞれがタスクとして分離しているのでどの順序で動かすか、と言うことが実行側で簡単に決められる
なんですが、その逆もしかりで
・環境が完全に独立しているため、互いのスクリプト内の変数が一切共有できない。
変数共有が必要な時はLuaを使用している親プログラム側で変数を共有する仕掛けを用意してそれが使用できるようにならなければならない
(シナリオ実行部からの実行情報を演出部に渡すときは一度システムにより与えられた命令により状態を投げなければ共有できない)
と言うことが起こります。
Luaは状態を初期化したときには予約語とそれにまつわる処理以外を全く持たない
前回のコードではそれを解消するためにLuaが標準で持っているライブラリをluaL_openlibs関数によりlua_Stateに与える、と言うことを行います。
ということで、
・Luaの環境初期化時には必ず対象のLua実行状態に合うように必要な処理を実装し、それをC言語(C++)側から与えなければならない
(簡単な算術の計算すらも四則系以外は作成直後は持っていない。それをluaL_openlibs関数などで設定する)
と言う問題があるのですが、これを逆手にとると
・作成する状態に応じて不必要な命令の定義を行わないことで空間の分離が出来る
(システム管理部とシナリオ実行部には普通の命令を与えておき、演出部だけ特殊な命令が実行できるようにする、と言った管理が出来る)
と言うことも考えられます。
ちなみに、C言語側から評価関数をデフォルトから別の物にすると四則演算系の結果すら別物に変えてしまう、と言うとんでもないことも出来たりします。
Luaは一度ファイルの実行を行うとグローバル空間に記述されたスクリプトが完了するまで戻ってこない
一応Luaにはコルーチンというユーザーが途中で処理を中断する機能があるのですが、どうもlongjmpを使っているという記述が引っかかっており、
ADVエンジンのスクリプトとして中断するにはちょっと信頼性があまりよろしくないと(個人的に)判断しています。
一度組み込んで使える、と言う判断が出来るようでしたら使った方が良いのですが・・・。
面倒でも
・Luaスクリプトには関数だけを記述する
・エントリポイントをスクリプトエンジン部が指定してそれを呼び出して実行する
・テキスト表示なども常に表示=>スクリプトをいったん終了というイベント駆動方式をとる方がよい
とした方がよいような気がします。
Luaにはテキストを簡易処理する機能はない
まあ、そんな機能を積んでいるスクリプトエンジンはADVシステムで使用されることを前提としない限りはまずないとおもいますが・・・。
これを解消するには
・基幹部をLuaで実行できるようにする
・シナリオ部を別ファイルに分離してLua以外の場所で読み込みを行い、解析結果をLuaのスクリプトに返す、と言う動作をとる
(このシナリオファイルをLuaとして扱うかどうかは考え物だが・・・。Luaとするならこれも状態を別に作って動作、と言うことで出来るかも)
と言うことが必要になります。
Luaには実行状態を保存する機能はない
これも、ADVシステムで使用されることを前提としない限りはまずないとおもいますが・・・。
というわけで、ADVエンジンとして必要となるその機能を補う必要があります。
保存として必要な項目は主に
・スクリプト上で設定として使用している項目の設定値
・実行されたシナリオファイルの実行履歴
・CGなどリソースファイルの読み込み履歴
が挙げられます。Luaスクリプト側で保存する仕掛けが必要になると思います。
一応Luaには関数をバイナリとして保存する機能はありますが、それでも
・実行状態そのものの保持(スタック状態、グローバル状態、実行位置、etc)
・パッチによるスクリプトの動的変更
を両方出来るか?と言われると特に後者がかなり厳しいですね。
Luaのエンジンは実行に関してはとてもよい
各種基本処理、メモリのガーベジコレクタ機能やメモリアロケータなど基本機能を直接与えることが出来るのが実行側から見るととてもいいですね。
また、エンジン実行の要となるC言語側とLua側とのやりとりが非常にやりやすく書くことが出来ます。
システム側にゲーム実行に関するいろいろな機能を直接実装したときにそれを呼び出して実行すると言う機能がとても使いやすいです。
(ADVシステムとして実装した後で別の種類のゲームの実行制御として使う、と言うこともやりやすい)
また、スクリプト言語としてのLuaもだいぶ普及しているので資料もそれなりの数になっていますので、これ以外で使用するとしても勉強しておくのもいいと思います。
こう考えると吉里吉里のTJSの考え方が有効
上で考えたLuaをADVエンジンのスクリプト部として使用することを考えるととても似ています。というか、元々TJSがおそらくそういう設計思想なのでしょうね・・・。
特にTJS本体とKAG(KAGParser)の連携がとても考えられているな~と思います。
と言うわけでLuaをADVシステムのスクリプトとして採用するにはこのような問題を乗り越える必要があります。
スクリプト本体の実行に関してはLuaは状態の管理などとても優秀ですのでうまいこと周りを固められればいいのではないでしょうか。
ライブラリのライセンスは問題なし
MIT Lisenceに準拠していますのでGPLだろうがソースコード非公開だろうが大丈夫です。
これに問題があると機能を調べるどころではないですからね・・・。