Visual Scripting(BOLT)でLuaスクリプトを動かすLuaFormulaを作ってみた

# 概要

UnityのVisual Scripting(旧BOLT)にはFomulaノードという数式を記述して計算結果を出力するノードがあるのですが、できるのはあくまで簡単な数式だけでできることが限られるなと思ったので。
せっかくなら同じような感じでLuaコードを実行できたらノード同士をつなげて実現するのは面倒だけどC#でコーディングするほどの事でもないような隙間を程よく埋められるんじゃないかと思い作ってみました。

![LuaFormula2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/f32d8858-e7da-9ba6-819e-4b7f64563f29.png)


# インストール

Lua実行環境に[xLua](https://github.com/Tencent/xLua)を利用しているため、xluaをインストールする必要があります。
xLuaのインストールは[ここからZipファイル](https://github.com/Tencent/xLua/releases/tag/v2.1.15f1)をダウンロードし、ZiPファイル内にあるAssetフォルダの中身をプロジェクト内のAssetフォルダにコピーするだけです。

LuaFormulaノードは[ここからソースコードをC#ファイルとして保存し](https://raw.githubusercontent.com/uniras/LuaFormula/main/LuaFormula.cs)、プロジェクトのAssetフォルダ内の何処かにコピーするだけです。

# 使い方

インストールが上手くいっていればノード検索でLuaとでも検索すればLua Formulaが候補に現れるはずです。
![LuaFormula1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/7f84236d-e7bc-b471-8e4d-a568ebcbd7db.png)

LuaFomulaを選ぶと以下のようなノードが出てくるはずです。
![LuaFormula2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/f32d8858-e7da-9ba6-819e-4b7f64563f29.png)

Inputsの値を変えることで入力データポートの数を0個から最大9個まで設定できます。
![LuaFormula10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/6222b010-9bd3-2dda-32c1-78b600dfd2a1.png)

入力データポートに接続したノードの内容はLua環境内ではグローバル変数A～I(大文字)に格納されています。
またグローバル変数R(これも大文字)に値を代入することで出力データポートResultに接続したノードにその値を渡すことができます。
テーブルを渡すとLuaTable型のオブジェクトが渡されるため、そのままではVisual Scriptingでは扱えなくなるので注意してください。

例えば入力データポートAとBに適当なIntegerノードを接続し、2つを足した結果をResultに出力したい場合は、
R=A+Bという風に入力します、実行すると画像のような結果になります。
![LuaFormula3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/8a30e9b4-4cb1-c17e-c70e-535c3324566f.png)

Lua実行中にエラーや例外が発生した場合は出力データポートのSuccessにはFalse、ErrorMessageにはエラーや例外の内容が渡されます。
その場合、Luaコードの実行は止まりますがVisual Scriptingのフローはそのまま継続します。
Unity Editor上で実行している場合はコンソールにエラーログが表示されます。
誤ったLuaコードを入力して実行した場合はこのような感じになります。
![LuaFormula4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/c5107e8d-f0f0-f750-7a1a-44ccba66fd84.png)

入力データポートにゲームオブジェクトやコンポーネントを渡してLuaコード上で操作することもできます。
Text(Legacy)コンポーネントの.textメンバを代入してテキストボックスの内容を取得するとこんな感じになります。
![LuaFormula5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/b01ac64a-3398-6f44-104c-9df157102a73.png)

LuaFormulaは意図しない参照を防ぐためデフォルトでは終了時にA～Iの内容をnull(nil)にクリアしますが、
複数のLuaFomulaノードに一つ一つ接続するのは面倒なので使いまわしたいといった場合は
インスペクタウインドウにあるCache ArgumentsチェックボックスにチェックをすることでA～Iの内容を保持することができます。
![LuaFormula6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/c74528bb-e088-c24f-c900-e02179a1ce5d.png)

これで以下のように次のLuaFormulaノードにも変数を引き継ぐことができます。
![LuaFormula7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/e132e9e2-019a-5f5f-0974-0cd42cccb921.png)

変数Aは保持したいが、次のLuaFomulaノードには新たに別のノードのデータを渡したいという時は以下のようにAに何も接続しないでおくと上書きされることなく変数Aを保持できます。
(Cache Argumentsチェックボックスにチェックは必要です)![LuaFormula8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/28a4e9d2-763d-a7fd-6bfe-35ee95009859.png)

Unity環境にLuaテーブルを保存できるように簡易のシリアライズ、デシリアライズ関数が使えるようにしてあります。
以下のような感じでテーブルの内容を文字列に変換したり、文字列からLuaテーブルに変換できたりします。
![LuaFormula9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41482/18145cc4-159d-17d0-0ab9-1ba69fcdd5d2.png)
あくまでこの機能は簡易版なので本格利用にはJSONを推奨します。
JSONはUnity側は(データ構造を定義するC#クラスを作る必要がありますが)標準で備えていますし、Lua側は[json.lua](https://github.com/rxi/json.lua)が[ソースコード](https://raw.githubusercontent.com/rxi/json.lua/master/json.lua)をjson.lua.txtとして保存しAttach/Resourcesにコピーするだけで使えるようになるので簡単です。