unityでXLuaを使ってADV機能を実装する

設計
unityでuniluaを使ってADV機能を実装する - Qiita
版の記事書きました動機ADVみたいな2Dの寸劇を制御するスクリプトが欲しかったのです。最初は…

unilua版はこちら、もう5年前ですか…言ってることがわかりませんね

僕の実装の基本はコルーチン

 IEnumerator CoDrama001()
    {
        yield return ShowMsg("hello, world!");
        yield return ShowMsg("bye");

    }

こんな風にガリガリ書いてけば、ADVとして動きそうですよね? 実際こうやって作ったゲームもありました。

しかし、ミニゲームならともかく、そこそこの規模のゲームでハードコードは悪いです。

処理変えるだけでコンパイル発生するし、プログラマ以外触れないし、AssetBundle化できないからモバイルのDLC的なこともできません。

歴史振り返ってみても、ノベルゲーの文章ハードコードするなんて聞いたことないですよね

そうだluaのコルーチン使おう

そこで僕は同じコルーチンでもluaのコルーチンに目をつけました。調べたらuntiyでも動くluaパーサー存在しました。ということはluaで上記のようなコード書けば、コンパイル無し、非プログラマも使える、AssetBundle化容易、と全ての問題解決します。

こういう思想で作ったのが初代uniluaベースのADV機能です。もちろん単純にコルーチン実行するわけでなく、もう少し複雑なことしてます。

XLuaでluaコルーチンをC#から実行してやる

xLua/Assets/XLua/Examples/06_Coroutine at master · Tencent/xLua
xLua is a lua programming solution for C# ( Unity, .Net, Mono) , it supports android, ios, windows, linux, osx, etc. - Tencent/xLua

xluaのコルーチンサンプルは残念な事に、luaからC#コルーチンを扱うものでした。逆は根性で調べました。

luaコルーチンをC#コルーチンに変換

how can i invoke lua coroutine in c# coroutine · Issue #499 · Tencent/xLua
i have some c# function IEnumerator coroutine , if i want invoke lua function which the lua function is coroutine. how can i implement this
libc = CS.DramaInterfaceFromLua;
function a()
    libc.ShowMsg(hello, world);
    libc.ShowMsg(bye);
end

local util = require 'xlua.util'
function get_co()
    return util.cs_generator(a);
end
IEnumlator CoMain(){
LuaEnv luaenv = new LuaEnv();
        luaenv.DoString(luascript);
        var getCoroutine = luaenv.Global.Get<System.Func<IEnumerator>>("get_co");
        var c = getCoroutine();
        yield return StartCoroutine(c);
}

こんな感じでしょうか、わかりやすいですね

get_coをコルーチンごとに用意するのはだるいですね。文字列引数でget_co(“a”)みたくできないでしょうか

resumeをassertで囲む

xLua/Assets/XLua/Doc/Faq_EN.md at master · Tencent/xLua
xLua is a lua programming solution for C# ( Unity, .Net, Mono) , it supports android, ios, windows, linux, osx, etc. - Tencent/xLua

luaコルーチンがエラーを出さない時があるらしいので

assert(coroutine.resume(co));

luaコルーチンをresumeする関数をC#で呼ぶ

libc = CS.DramaInterfaceFromLua;
function a()
    libc.ShowMsg(hello, world);
    libc.ShowMsg(bye);
end

co = coroutine.create(a);
function resume()
    coroutine.resume(co);
end
var resume = luaenv.Global.Get<System.Action>("resume");
        resume();

このままだと終了判定が取れないので、coroutine.status()をreturnするようにするか、status()を取得する関数を作るのがよいですね

まとめ

xluaでもコルーチンベースのADV機能実装できそうです