MoonsharpとLuaとUnityについて学ぶ
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* 目次 [#d070a7cf]
#contents
* Moonsharpとは [#df0cc95f]
一言でいえば、レベルデザイン必要なゲームを開発するなら、...
わかりやすくいうと、これを入れない設計でゲームをつくると...
UnityでLuaを使えるようにするプラグインである。
Asset Storeを開き、
MoonSharp
と検索すると出てきます。
https://assetstore.unity.com/packages/tools/moonsharp-337...
MoonSharpは、.NET、Mono、Xamarin、Unity3Dプラットフォーム...
* 特徴 [#g6a14b51]
- Lua 5.2との99%の互換性(サポートされていない唯一の機能...
- metaluaスタイルの無名関数(ラムダスタイル)のサポート
- 使いやすいAPI
- Visual Studio Codeのデバッガサポート(PCLターゲットはサ...
- Webブラウザとフラッシュでアクセス可能なリモートデバッガ...
- .NET 3.5、.NET 4.x、.NET Core、Mono、Xamarin、Unity3Dで...
- iOSのようなAhead-of-timeプラットフォームで動作
- IL2CPPに変換されたコードで動作
- .NET 4.xのポータブルクラスライブラリを必要とするプラッ...
- 外部の依存関係がなく、可能な限り少ないターゲットで実装
- サポートされている場合、ランタイムコード生成によるCLRオ...
- メソッド、拡張メソッド、オーバーロード、フィールド、プ...
- 非常に少ない例外(主に「debug」モジュールにある)と少数...
- .NET 4.xターゲット用の非同期メソッド
- 難読化とランタイム時のより迅速な解析のためのバイトコー...
- JSONとLuaテーブルの間で変換するための(依存関係のない)...
- スクリプトがアクセスできるものをサンドボックス化するた...
- 使いやすいエラー処理(スクリプトエラーは例外です)
- コルーチンのサポート(C#イテレータとしてのコルーチンの...
- REPLインタプリタ、および数行のコードで独自のREPLを簡単...
- http://www.moonsharp.org にある完全なXMLヘルプとチュー...
* MoonSharpと標準Luaの違い [#e0052ec6]
http://www.moonsharp.org/moonluadifferences.html
を参照してください。
ダウンロード、情報、チュートリアルなどについては、http://...
*** ライセンス [#p3b97abd]
プログラムとライブラリは、3条項BSDライセンスの下でリリー...
文字列ライブラリの一部は、KopiLuaプロジェクト(https://gi...
* 使用方法 [#rc0da492]
ライブラリの使用は次のように簡単です:
double MoonSharpFactorial()
{
string script = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end
return fact(5)";
DynValue res = Script.RunString(script);
return res.Number;
}
より詳細なチュートリアル、サンプルなどについては、http://...
** 公式サイト [#ae77951f]
https://www.moonsharp.org/
*** Github [#h2f29b43]
https://github.com/moonsharp-devs/moonsharp
* チュートリアル [#e115d97d]
本家のチュートリアルを翻訳しました。
** 元記事 [#m4521d40]
https://www.moonsharp.org/getting_started.html
** チュートリアルをはじめるにあたって [#dc75bb7e]
このチュートリアルでは、UnityでMoonSharpの簡単さと強力さ...
とりあえず、始めましょう。
このチュートリアルでは、LuaとC#を知っていることを前提とし...
*** ステップ1:UnityでMoonSharpを入手する [#sfc07f66]
最初のステップは、UnityでMoonSharpを入手することです。
Unity Asset Storeのパッケージは現在承認待ちで、承認され次...
MoonSharp配布物のinterpreter/net35フォルダに含まれているM...
Windows StoreアプリやWindows Phoneのサポートが必要な場合...
次に、このガイドに従ってください。
その後、Unity EditorからMoonSharp.Interpreter.dllを参照と...
注:IL2CPPプロジェクトでMoonSharpを使用する場合は、以下の...
<linker>
<assembly fullname="MoonSharp.Interpreter">
<type fullname="MoonSharp.*" preserve="all" />
</assembly>
</linker>
*** ステップ2:名前空間のインポート [#m972361d]
コードの先頭に以下の行を追加して、MoonSharp.Interpreter名...
using MoonSharp.Interpreter;
*** ステップ3:スクリプトの呼び出し [#u47bd259]
ここでは、MoonSharpを使用して階乗を計算するMoonSharpFacto...
double MoonSharpFactorial()
{
string script = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end
Copy code return fact(5)";
DynValue res = Script.RunString(script);
return res.Number;
}
*** ステップ4:完了! [#nf07c737]
もちろん、コードを実行するには、Unity C#スクリプトの他の...
これで、UnityでMoonSharpを使うための準備が整いました。他...
** スクリプトを保持する [#re6a0baf]
前回のチュートリアルでは、MoonSharpに初めて触れました。ス...
*** ステップ1: 前回のチュートリアルで行ったことをすべてや...
真面目な話、ここではもう少し高度な概念を学んでいますが、...
*** ステップ2: コードを変更してScriptオブジェクトを作成す...
最初の変更点は、静的メソッドを使用する代わりにScriptオブ...
double MoonSharpFactorial()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end
return fact(5)";
Script script = new Script();
DynValue res = script.DoString(scriptCode);
return res.Number;
}
*** ステップ2: グローバル環境にアクセスする [#te57efec]
スクリプトオブジェクトを持っているので、関数が動作するグ...
例えば、fact関数への入力を変更して、プログラムがどの数の...
double MoonSharpFactorial()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end
return fact(mynumber)";
Script script = new Script();
script.Globals["mynumber"] = 7;
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ご覧の通り、script.Globalsテーブルを単純な構文で参照する...
*** ステップ2: 関数を直接呼び出す [#ya81cef6]
外部から選択した数値の階乗をMoonSharpで計算する方法を学び...
でも、そのようにやるのは汚いハックのように見えます(それ...
以下は、C#からLua関数を呼び出す方法です。
double MoonSharpFactorial2()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end";
Script script = new Script();
script.DoString(scriptCode);
DynValue res = script.Call(script.Globals["fact"], 4);
return res.Number;
}
何をしたのか見てみましょう。
まず、スクリプトの最後のreturnを削除しました。
残しておくこともできましたが、任意のパラメータでfactを呼...
この時点で、
script.DoString(...)
の呼び出しはファイルを実行し、グローバル環境にfact関数を...
そして、この行を導入しました。
DynValue res = script.Call(script.Globals["fact"], 4);
これは、スクリプトのグローバルからfact関数を取得し、4をパ...
もっと良い(つまり、パフォーマンスの良い)方法があります...
factの関数は何度でも呼び出せることに注意してください。Scr...
** DynValueのすべて [#w1153ae3]
- すべてはDynValueであり、DynValueである
DynValueの概念はMoonSharpの根幹にあり、これまではあまり触...
タイトルにもあるように、MoonSharpの(ほぼ)すべてがDynVal...
DynValueは、スクリプト内の値を表し、その型に関わらず、テ...
では、まず前回のチュートリアルの最後のステップから始めて...
*** ステップ1: 前回のチュートリアルで行ったことをすべてや...
再び、前回の最後のステップから始めます。やったよね?
リファレンスドキュメントはここで入手できます。
*** ステップ2: fact関数をDynValueで取得する [#j049e11e]
最初の変更点として、fact変数を別の方法で取得します。
double MoonSharpFactorial()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end";
Script script = new Script();
script.DoString(scriptCode);
DynValue luaFactFunction = script.Globals.Get("fact");
DynValue res = script.Call(luaFactFunction, 4);
return res.Number;
}
この行について少し説明しましょう。
DynValue luaFactFunction = script.Globals.Get("fact");
これは、スクリプトのグローバルからfact関数を取得します。
Getメソッドは、インデクサープロパティとは反対に、DynValue...
インデクサーは、代わりにSystem.Objectに変換しようとします。
この場合、DynValueに関心があるので、Getメソッドを使用しま...
*** ステップ3: 数値をDynValueで取得する [#afda98b8]
さて、もう1つの変換を避けることにも関心があるなら、Callメ...
ここでは必要ありませんが、他の場所では必要になるかもしれ...
double MoonSharpFactorial2()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end";
Script script = new Script();
script.DoString(scriptCode);
DynValue luaFactFunction = script.Globals.Get("fact");
DynValue res = script.Call(luaFactFunction, DynValue.N...
return res.Number;
}
つまり、数値を以下のように置き換えました。
DynValue.NewNumber(4)
DynValueには、"New"で始まる多くのファクトリメソッドがあり...
これらを使用して、最初から値を作成できます。
また、便利なFromObjectメソッドもあります。これはオブジェ...
*** ステップ4: DataTypeの理解 [#vbad2568]
DynValueで最も重要なプロパティの1つはTypeです。
Typeプロパティは列挙型で、DynValueにどのような種類のデー...
DynValueに何が含まれているかを知りたい場合は、いつでもTyp...
// 新しい数値を作成
DynValue v1 = DynValue.NewNumber(1);
// 新しい文字列を作成
DynValue v2 = DynValue.NewString("ciao");
// 自動変換を使用して別の文字列を作成
DynValue v3 = DynValue.FromObject(new Script(), "hello");
// Number - String - String と表示される
Console.WriteLine("{0} - {1} - {2}", v1.Type, v2.Type, v...
// Number - String - 0になると期待すべきではないゴミの数...
Console.WriteLine("{0} - {1} - {2}", v1.Number, v2.Strin...
DynValueの一部のプロパティは、値が特定の型の場合にのみ意...
例えば、NumberプロパティはDataType.Numberの場合にのみ意味...
DynValueの中身が確実にわかっていない限り、そのプロパティ...
DynValueが特定の型を含んでいると想定しているのに、別の型...
*** ステップ5: タプル [#gddb0564]
ご存知のように(あるいは知っておくべきですが)、Luaでは関...
これを処理するために、特別なDynValue型(DataType.Tuple)...
これは聞こえるよりも簡単です。
DynValue ret = Script.RunString("return true, 'ciao', 2*...
// "Tuple" と表示される
Console.WriteLine("{0}", ret.Type);
// 以下が表示される:
// Boolean = true
// String = "ciao"
// Number = 6
for (int i = 0; i < ret.Tuple.Length; i++)
Console.WriteLine("{0} = {1}", ret.Tuple[i].Type, ret....
終わりに
DynValuesについて終わりです。
まだまだ学ぶべきことはたくさんありますが、このトピックを...
すべてがこれを中心に回っているので、これを肝に銘じておい...
** C#をコールバックする [#o1bf9b18]
- ..そしてF#、VB.NET、C++/CLI、Booなども
スクリプトは、アプリケーション自体に実装された構成要素か...
ビジネスアプリケーション、ビデオゲーム、またはある種のツ...
そして、手続き型プログラミングの基本的な構成要素は関数で...
*** 演習1、ステップ1: 階乗に飽きるな [#g99c9a42]
これまで使ってきた標準的な階乗スクリプトで基礎を押さえま...
private static double CallbackTest()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n * fact(n - 1);
end
end";
Script script = new Script();
script.DoString(scriptCode);
DynValue res = script.Call(script.Globals["fact"], 4);
return res.Number;
}
*** 演習1、ステップ2: 乗算関数をカスタマイズする [#o01730...
さて、乗算をホストアプリケーションのAPI関数で実装したいと...
この場合、そうする目的はありませんが、学ぶためにここにい...
private static int Mul(int a, int b)
{
return a * b;
}
private static double CallbackTest()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return Mul(n, fact(n - 1));
end
end";
Script script = new Script();
script.Globals["Mul"] = (Func<int, int, int>)Mul;
script.DoString(scriptCode);
DynValue res = script.Call(script.Globals["fact"], 4);
return res.Number;
}
それだけです!
script.Globals["Mul"] = (Func<int, int, int>)Mul;
これにより、グローバル環境のMul変数が、アプリケーションの...
ここでは、C#コンパイラを満足させるために、デリゲートをFun...
デリゲートをSystem.Objectにキャストするために使用する方法...
また、メソッドをstaticに定義しましたが、この場合、それら...
インスタンスメソッドも問題ありません。
*** 演習2: 数値のシーケンスを返す [#ved358ee]
問題: 整数のシーケンスを返すAPI関数を用意する。スクリプト...
private static IEnumerable<int> GetNumbers()
{
for (int i = 1; i <= 10; i++)
yield return i;
}
private static double EnumerableTest()
{
string scriptCode = @"
total = 0;
for i in getNumbers() do
total = total + i;
end
return total;
";
Script script = new Script();
script.Globals["getNumbers"] = (Func<IEnumerable<int...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ここでも、特に難しいことはありません。
IEnumerable(またはIEnumerator)が、スクリプトを実行する...
スクリプトには直接実行可能なコードが含まれているため、Cal...
これを覚えておいてください。
DoStringとDoFileは、スクリプトに含まれるコードを即座に実...
注意すべき点が1つあります。MoonSharpは、System.Collection...
つまり、ジェネリックではないバリアントです。
何らかの理由でジェネリックイテレータを実装する際にジェネ...
上記のように、すべての標準コレクション型とイテレータメソ...
*** テーブルを返す [#me086187]
問題: 今度は整数のシーケンスをテーブルで返すAPI関数を用意...
private static List<int> GetNumberList()
{
List<int> lst = new List<int>();
for (int i = 1; i <= 10; i++)
lst.Add(i);
return lst;
}
private static double TableTest1()
{
string scriptCode = @"
total = 0;
tbl = getNumbers()
for _, i in ipairs(tbl) do
total = total + i;
end
return total;
";
Script script = new Script();
script.Globals["getNumbers"] = (Func<List<int>>)GetN...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ここでは、List<int>がLuaテーブルに自動的に変換される様子...
結果のテーブルは、Luaテーブルが通常そうであるように、1か...
ただし、もっと良い方法があります。
関数内で直接Luaテーブルを構築することができます。
private static Table GetNumberTable(Script script)
{
Table tbl = new Table(script);
for (int i = 1; i <= 10; i++)
tbl[i] = i;
return tbl;
}
private static double TableTest2()
{
string scriptCode = @"
total = 0;
tbl = getNumbers()
for _, i in ipairs(tbl) do
total = total + i;
end
return total;
";
Script script = new Script();
script.Globals["getNumbers"] = (Func<Script, Table>)...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
Tableオブジェクトを使用してテーブルを操作するのがいかに簡...
ただし、注意すべき点が2つあります。
新しいTableオブジェクトを作成するには、実行中のスクリプト...
CLR関数にScriptパラメータがあり、それがLuaスクリプトで利...
これは、(このように使用される可能性は低いですが)ScriptE...
これらが何をするのかわからなくても心配しないでください。
MoonSharpの基本を理解するのに必要ありません!
良い習慣として、可能な限りScriptオブジェクトを保持するよ...
(テーブルの作成など)Scriptオブジェクトを使用してのみ実...
*** テーブルを受け入れる [#p43434d6]
テーブルは自動的にList<T>に変換されます。
例えば、
public static double TableTestReverse()
{
string scriptCode = @"
return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
";
Script script = new Script();
script.Globals["dosum"] = (Func<List<int>, int>)(l => l...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ただし、これによって一部のプラットフォーム(具体的にはiOS...
この問題を回避する方法はたくさんありますが(他のチュート...
public static double TableTestReverseSafer()
{
string scriptCode = @"
return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
";
Script script = new Script();
script.Globals["dosum"] = (Func<List<object>, int>)(l =...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
さらに高速な別の方法は、Tableオブジェクトを使用することで...
static double Sum(Table t)
{
var nums = from v in t.Values
where v.Type == DataType.Number
select v.Number;
return nums.Sum();
}
private static double TableTestReverseWithTable()
{
string scriptCode = @"
return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
";
Script script = new Script();
script.Globals["dosum"] = (Func<Table, double>)Sum;
DynValue res = script.DoString(scriptCode);
return res.Number;
}
しかし、ここではDynValue(s)を扱う必要があります。
これらすべてを理解するには、MoonSharpがLuaの型をC#の型に...
次の部分で説明します。
** 自動変換の説明 [#zdd8f29e]
- ..今回はコードなし
MoonSharpとCLRの統合についてさらに掘り下げる前に、型がど...
残念ながら、逆方向は順方向とは大きく異なるので、2つを別々...
これは少し複雑すぎませんか? - あなたはそう尋ねるかもしれ...
確かにそうです。
自動的なものは良いですが、失敗すると、ひどく複雑な方法で...
2つの方法があります:DynValueをそのまま使用するか、カスタ...
これらの解決策は、正気と単純さを得るだけでなく、自動変換...
*** カスタムコンバーター [#iaa65800]
変換プロセスをカスタマイズすることは可能ですが、設定はグ...
変換をカスタマイズするには、
Script.GlobalOptions.CustomConverters
の適切なコールバックを設定するだけです。
例えば、CLRからスクリプトへの変換が行われるときに、すべての
StringBuilder
オブジェクトを大文字の文字列に変換したい場合は、次のよう...
Script.GlobalOptions.CustomConverters.SetClrToScriptCust...
v => DynValue.NewString(v.ToString().ToUpper()));
テーブルがIList<int>に一致する必要がある場合に、テーブル...
Script.GlobalOptions.CustomConverters.SetScriptToClrCust...
v => new List<int>() { ... });
コンバーターがnullを返した場合、システムはカスタムコンバ...
*** CLR型からMoonSharp型への自動変換 [#y6c7cab4]
この変換は、次の状況で適用されます。
- スクリプトによって呼び出された関数からオブジェクトを返...
- ユーザーデータのプロパティからオブジェクトを返すとき
- インデックス演算子を使用してテーブルに値を設定するとき
- DynValue.FromObjectを呼び出すとき
- DynValueの代わりにSystem.Objectを取る関数のオーバーロー...
この変換は実際にはかなり簡単です。次の表は、変換を説明し...
| CLR型 | C#のわかりやす...
|----------------------------------------|---------------...
| void | ...
| null | ...
| MoonSharp.Interpreter.DynValue | ...
| System.SByte | sbyte ...
| System.Byte | byte ...
| System.Int16 | short ...
| System.UInt16 | ushort ...
| System.Int32 | int ...
| System.UInt32 | uint ...
| System.Int64 | long ...
| System.UInt64 | ulong ...
| System.Single | float ...
| System.Decimal | decimal ...
| System.Double | double ...
| System.Boolean | bool ...
| System.String | string ...
| System.Text.StringBuilder | ...
| System.Char | char ...
| MoonSharp.Interpreter.Table | ...
| MoonSharp.Interpreter.CallbackFunction | ...
| System.Delegate | ...
| System.Object | object ...
| System.Type | ...
| MoonSharp.Interpreter.Closure | ...
| System.Reflection.MethodInfo | ...
| System.Collections.IList | ...
| System.Collections.IDictionary | ...
| System.Collections.IEnumerable | ...
| System.Collections.IEnumerator | ...
これには、コレクションのかなり良いカバレッジが含まれてい...
独自のコレクションを書く場合は、これらの非ジェネリックイ...
このロジックを使用して変換できない値はすべて、ScriptRunti...
*** MoonSharp型からCLR型への標準の自動変換 [#b443915a]
反対の変換はかなり複雑です。
実際、2つの異なる変換パスがあります。
「標準」の変換パスと、「制約付き」の変換パスです。
最初の変換パスは、実際に何を受け取りたいかを指定せずにDyn...
これは以下の場合に使用されます。
- DynValue.ToObjectを呼び出すとき
- インデクサーを使用してテーブルから値を取得するとき
- 制約付き変換の特定のサブケース(下記参照)
ここでは、デフォルトの変換を見ていきます。実際には簡単で...
| MoonSharp型 | CLR型 ...
|----------------------------------------|---------------...
| nil | null ...
| boolean | System.Boolean...
| number | System.Double ...
| string | System.String ...
| function | MoonSharp.Inte...
| function | MoonSharp.Inte...
| table | MoonSharp.Inte...
| tuple | MoonSharp.Inte...
| userdata | (special) ...
このロジックを使用して変換できない値はすべて、ScriptRunti...
*** MoonSharp型からCLR型への制約付き自動変換 [#b3fb4110]
しかし、制約付き自動変換ははるかに複雑です。この場合、Moo...
これは以下の場合に使用されます。
- DynValue.ToObject<T>を呼び出すとき
- CLR関数呼び出しやプロパティ設定でスクリプト値をパラメー...
MoonSharpは値の変換に非常に努力しますが、特にテーブルが関...
この場合、変換は単純なマッピングのテーブルではなく、プロ...
*** 特殊なケース [#h25b1ae1]
- ターゲットがMoonSharp.Interpreter.DynValue型の場合は変...
- ターゲットがSystem.Object型の場合は、前述のデフォルトの...
- マッピングされるnil値の場合、nullは参照型とnullable値型...
- 値が提供されていない場合は、可能であればデフォルト値が...
*** 文字列 [#gde47277]
文字列は、System.String、System.Text.StringBuilder、Syste...
*** ブール値 [#lb1bcc8c]
ブール値は、System.BooleanやSystem.Nullable<System.Boolea...
*** 数値 [#dc22c32c]
数値は、System.SByte、System.Byte、System.Int16、System.U...
*** 関数 [#z9738d47]
スクリプト関数は、MoonSharp.Interpreter.ClosureまたはMoon...
*** ユーザーデータ [#jbe4344d]
ユーザーデータは、「静的」でない場合にのみ変換されます(...
また、オブジェクトのToString()メソッドを呼び出すことで、S...
*** テーブル [#g19e08d9]
テーブルは以下に変換できます。
- MoonSharp.Interpreter.Table - もちろん
- Dictionary<DynValue, DynValue>から割り当て可能な型。
- Dictionary<object, object>から割り当て可能な型。キーと...
- List<DynValue>から割り当て可能な型。
- List<object>から割り当て可能な型。要素は、デフォルトの...
- DynValue[]から割り当て可能な型。
- object[]から割り当て可能な型。要素は、デフォルトのマッ...
- T[]、IList<T>、List<T>、ICollection<T>、IEnumerable<T>...
- IDictionary<K,V>、Dictionary<K,V>。ここで、KとVは変換可...
ジェネリックや型付き配列への変換には、次の制限があること...
- リフレクションを使用して実行時に型が作成されるため、速...
- アイテムの型が値型の場合、iOSやAOTモードで実行される他...
これらの問題を補うために、開発の後半でカスタムコンバータ...
一部の変換(List<int>への変換など)は、Unity/iOSなどのAOT...
iOSなどのAOTプラットフォームをターゲットにする場合は、値...
** オブジェクトの共有 [#obbc6f3a]
- LuaとC#はお互いに話す
注:このページに記載されている一部の機能は、masterブラン...
MoonSharpの便利な機能の1つは、.NETオブジェクトをスクリプ...
デフォルトでは、型はすべてのパブリックメソッド、パブリッ...
MoonSharpVisibleアトリビュートを使用して、このデフォルト...
CLRコードとスクリプトコード間のインターフェイスとして専用...
多くのデザインパターン(アダプター、ファサード、プロキシ...
これは特に以下のために重要です。
- スクリプトができること、できないことを制限する(セキュ...
- スクリプト作成者にとって意味のあるインターフェイスを提...
- インターフェイスを別々に文書化する
- スクリプトを破ることなく、内部ロジックとモデルを変更で...
これらの理由から、MoonSharpはデフォルトで、スクリプトで使...
スクリプトを信頼できるシナリオでは、`
UserData.RegistrationPolicy = InteropRegistrationPolicy....
を使用して自動登録をグローバルに有効にできます。
危険なので、警告しておきます。
*** メニューにあるもの [#dda0ae94]
では、メニューにあるものを見てみましょう。
- まず、型記述子について説明しましょう - 舞台裏で何が起こ...
- シンプルに保つ - 始めるための最も簡単な方法
- 少し複雑 - 少し複雑さと詳細を加えて掘り下げる
- 静的メンバーの呼び出し - 静的メンバーを呼び出す方法
- ':' と '.' のどちらを使うべきか - メソッドの呼び出し方...
- オーバーロード - オーバーロードがどのように処理されるか
- ByRefパラメーター(C#のref/out) - ref/outパラメーター...
- インデクサー - インデクサーの処理方法
- ユーザーデータ上の演算子とメタメソッド - 演算子のオーバ...
- 拡張メソッド - 拡張メソッドの使用方法
- イベント - イベントの使用方法
- インターオペラビリティアクセスモード - インターオペラビ...
- MoonSharpHiddenとMoonSharpVisibleによる可視性の変更 - ...
- メンバーの削除 - メンバーの可視性を削除する方法
たくさんありますね。では、始めましょう。
*** 型記述子 [#ce23a6ed]
まず、型記述子について説明しましょう
最初に、インターオペラビリティがどのように実装されている...
すべてのCLR型は、CLR型をスクリプトに記述する役割を持つ「...
型をインターオペラビリティ用に登録するとは、型を記述子(M...
この記述子は、メソッド、プロパティなどのディスパッチに使...
次のセクション以降では、MoonSharpが提供する「自動」記述子...
*** 独自の記述子を実装したい場合 [#i28f4d6d]
独自の記述子を実装したい場合(簡単ではなく、必要でない限...
- 独自の型を記述するためのアドホックなIUserDataDescriptor...
- 型にIUserDataTypeインターフェイスを実装させる。これは簡...
- StandardUserDataDescriptorを拡張または埋め込み、必要な...
記述子の作成を助けるために、次のクラスが利用できます。
- StandardUserDataDescriptor - これはMoonSharpが実装する...
- StandardUserDataMethodDescriptor - これは単一のメソッド...
- StandardUserDataOverloadedMethodDescriptor - これはオー...
- StandardUserDataPropertyDescriptor - これは単一のプロパ...
- StandardUserDataFieldDescriptor - これは単一のフィール...
*** ユーザーデータとしての値型とのインターオペラビリティ...
値型をパラメーターとして渡す関数を呼び出す場合と同様に、...
繰り返しになりますが、これは値型の標準的な動作と変わりま...
さらに、値型は参照型ほどの最適化の範囲をサポートしていな...
*** シンプルに保つ [#b3bac791]
では、最初の例を見てみましょう。
[MoonSharpUserData]
class MyClass
{
public double calcHypotenuse(double a, double b)
{
return Math.Sqrt(a * a + b * b);
}
}
double CallMyClass1()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// MoonSharpUserData型をすべて自動的に登録
UserData.RegisterAssembly();
Script script = new Script();
// MyClassのインスタンスをスクリプトのグローバルに渡す
script.Globals["obj"] = new MyClass();
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ここでは以下のことを行っています。
- [MoonSharpUserData]アトリビュートを持つクラスを定義
- MyClassオブジェクトのインスタンスをスクリプトのグローバ...
- スクリプトからMyClassのメソッドを呼び出す。コールバック...
*** 少し複雑 [#x8b60ac6]
もう少し複雑な例を試してみましょう。
class MyClass
{
public double CalcHypotenuse(double a, double b)
{
return Math.Sqrt(a * a + b * b);
}
}
static double CallMyClass2()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// MyClassだけを明示的に登録
UserData.RegisterType<MyClass>();
Script script = new Script();
// ユーザーデータを明示的に作成
DynValue obj = UserData.Create(new MyClass());
script.Globals.Set("obj", obj);
DynValue res = script.DoString(scriptCode);
return res.Number;
}
*** 大きな違い [#a756817e]
大きな違いは以下の通りです。
- [MoonSharpUserData]アトリビュートはありません。もう必要...
- RegisterAssemblyの代わりに、RegisterTypeを呼び出して特...
- ユーザーデータのDynValueを明示的に作成します。
また、C#コードではメソッドがCalcHypotenuse と呼ばれていま...
他のバージョンが存在しない限り、MoonSharpは異なる言語の構...
*** 静的メンバーの呼び出し [#b88a2ae1]
calcHypotenuse メソッドが静的であるとしましょう。
[MoonSharpUserData]
class MyClassStatic
{
public static double calcHypotenuse(double a, double...
{
return Math.Sqrt(a * a + b * b);
}
}
*** 呼び出す方法 [#x240cc3a]
これを呼び出すには2つの方法があります。
*** 方法1 - 静的メソッドはインスタンスから透過的に呼び出...
double MyClassStaticThroughInstance()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// MoonSharpUserData型をすべて自動的に登録
UserData.RegisterAssembly();
Script script = new Script();
script.Globals["obj"] = new MyClassStatic();
DynValue res = script.DoString(scriptCode);
return res.Number;
}
*** 別の方法 [#of33f4f5]
- 型を直接渡す(またはUserData.CreateStaticメソッドを使...
double MyClassStaticThroughPlaceholder()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// MoonSharpUserData型をすべて自動的に登録
UserData.RegisterAssembly();
Script script = new Script();
script.Globals["obj"] = typeof(MyClassStatic);
DynValue res = script.DoString(scriptCode);
return res.Number;
}
':' と '.' のどちらを使うべきか
上記の例のコードを考えると、この構文を使うべきでしょうか
return obj.calcHypotenuse(3, 4);
それともこちらでしょうか?
return obj:calcHypotenuse(3, 4);
99.999%の場合、違いはありません。MoonSharpは、ユーザーデ...
*** 違いが出る可能性があるコーナーケース [#r13135cc]
違いが出る可能性があるコーナーケースがあります。たとえば...
*** オーバーロード [#v6fea100]
オーバーロードされたメソッドがサポートされています。オー...
これは、いくつかの曖昧さが存在するためです。たとえば、オ...
void DoSomething(int i) { ... }
void DoSomething(float f) { ... }
Luaのすべての数値がdoubleであることを考えると、MoonSharp...
この問題を解決するために、MoonSharpは入力型に対するすべて...
MoonSharpは、ヒューリスティックの重みを可能な限り安定させ...
とは言え、MoonSharpが考えているのとは異なるオーバーロード...
そのため、オーバーロードが同等の処理を行うようにすること...
- ByRefパラメーター(C#のref/out)
- ByRefメソッドパラメーター
* 参考 [#l6580144]
** MoonSharpによるUnityとLuaの連携 [#r91a70b3]
https://qiita.com/massu2357/items/425cc93b5965ceea29aa
終了行:
* 目次 [#d070a7cf]
#contents
* Moonsharpとは [#df0cc95f]
一言でいえば、レベルデザイン必要なゲームを開発するなら、...
わかりやすくいうと、これを入れない設計でゲームをつくると...
UnityでLuaを使えるようにするプラグインである。
Asset Storeを開き、
MoonSharp
と検索すると出てきます。
https://assetstore.unity.com/packages/tools/moonsharp-337...
MoonSharpは、.NET、Mono、Xamarin、Unity3Dプラットフォーム...
* 特徴 [#g6a14b51]
- Lua 5.2との99%の互換性(サポートされていない唯一の機能...
- metaluaスタイルの無名関数(ラムダスタイル)のサポート
- 使いやすいAPI
- Visual Studio Codeのデバッガサポート(PCLターゲットはサ...
- Webブラウザとフラッシュでアクセス可能なリモートデバッガ...
- .NET 3.5、.NET 4.x、.NET Core、Mono、Xamarin、Unity3Dで...
- iOSのようなAhead-of-timeプラットフォームで動作
- IL2CPPに変換されたコードで動作
- .NET 4.xのポータブルクラスライブラリを必要とするプラッ...
- 外部の依存関係がなく、可能な限り少ないターゲットで実装
- サポートされている場合、ランタイムコード生成によるCLRオ...
- メソッド、拡張メソッド、オーバーロード、フィールド、プ...
- 非常に少ない例外(主に「debug」モジュールにある)と少数...
- .NET 4.xターゲット用の非同期メソッド
- 難読化とランタイム時のより迅速な解析のためのバイトコー...
- JSONとLuaテーブルの間で変換するための(依存関係のない)...
- スクリプトがアクセスできるものをサンドボックス化するた...
- 使いやすいエラー処理(スクリプトエラーは例外です)
- コルーチンのサポート(C#イテレータとしてのコルーチンの...
- REPLインタプリタ、および数行のコードで独自のREPLを簡単...
- http://www.moonsharp.org にある完全なXMLヘルプとチュー...
* MoonSharpと標準Luaの違い [#e0052ec6]
http://www.moonsharp.org/moonluadifferences.html
を参照してください。
ダウンロード、情報、チュートリアルなどについては、http://...
*** ライセンス [#p3b97abd]
プログラムとライブラリは、3条項BSDライセンスの下でリリー...
文字列ライブラリの一部は、KopiLuaプロジェクト(https://gi...
* 使用方法 [#rc0da492]
ライブラリの使用は次のように簡単です:
double MoonSharpFactorial()
{
string script = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end
return fact(5)";
DynValue res = Script.RunString(script);
return res.Number;
}
より詳細なチュートリアル、サンプルなどについては、http://...
** 公式サイト [#ae77951f]
https://www.moonsharp.org/
*** Github [#h2f29b43]
https://github.com/moonsharp-devs/moonsharp
* チュートリアル [#e115d97d]
本家のチュートリアルを翻訳しました。
** 元記事 [#m4521d40]
https://www.moonsharp.org/getting_started.html
** チュートリアルをはじめるにあたって [#dc75bb7e]
このチュートリアルでは、UnityでMoonSharpの簡単さと強力さ...
とりあえず、始めましょう。
このチュートリアルでは、LuaとC#を知っていることを前提とし...
*** ステップ1:UnityでMoonSharpを入手する [#sfc07f66]
最初のステップは、UnityでMoonSharpを入手することです。
Unity Asset Storeのパッケージは現在承認待ちで、承認され次...
MoonSharp配布物のinterpreter/net35フォルダに含まれているM...
Windows StoreアプリやWindows Phoneのサポートが必要な場合...
次に、このガイドに従ってください。
その後、Unity EditorからMoonSharp.Interpreter.dllを参照と...
注:IL2CPPプロジェクトでMoonSharpを使用する場合は、以下の...
<linker>
<assembly fullname="MoonSharp.Interpreter">
<type fullname="MoonSharp.*" preserve="all" />
</assembly>
</linker>
*** ステップ2:名前空間のインポート [#m972361d]
コードの先頭に以下の行を追加して、MoonSharp.Interpreter名...
using MoonSharp.Interpreter;
*** ステップ3:スクリプトの呼び出し [#u47bd259]
ここでは、MoonSharpを使用して階乗を計算するMoonSharpFacto...
double MoonSharpFactorial()
{
string script = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end
Copy code return fact(5)";
DynValue res = Script.RunString(script);
return res.Number;
}
*** ステップ4:完了! [#nf07c737]
もちろん、コードを実行するには、Unity C#スクリプトの他の...
これで、UnityでMoonSharpを使うための準備が整いました。他...
** スクリプトを保持する [#re6a0baf]
前回のチュートリアルでは、MoonSharpに初めて触れました。ス...
*** ステップ1: 前回のチュートリアルで行ったことをすべてや...
真面目な話、ここではもう少し高度な概念を学んでいますが、...
*** ステップ2: コードを変更してScriptオブジェクトを作成す...
最初の変更点は、静的メソッドを使用する代わりにScriptオブ...
double MoonSharpFactorial()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end
return fact(5)";
Script script = new Script();
DynValue res = script.DoString(scriptCode);
return res.Number;
}
*** ステップ2: グローバル環境にアクセスする [#te57efec]
スクリプトオブジェクトを持っているので、関数が動作するグ...
例えば、fact関数への入力を変更して、プログラムがどの数の...
double MoonSharpFactorial()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end
return fact(mynumber)";
Script script = new Script();
script.Globals["mynumber"] = 7;
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ご覧の通り、script.Globalsテーブルを単純な構文で参照する...
*** ステップ2: 関数を直接呼び出す [#ya81cef6]
外部から選択した数値の階乗をMoonSharpで計算する方法を学び...
でも、そのようにやるのは汚いハックのように見えます(それ...
以下は、C#からLua関数を呼び出す方法です。
double MoonSharpFactorial2()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end";
Script script = new Script();
script.DoString(scriptCode);
DynValue res = script.Call(script.Globals["fact"], 4);
return res.Number;
}
何をしたのか見てみましょう。
まず、スクリプトの最後のreturnを削除しました。
残しておくこともできましたが、任意のパラメータでfactを呼...
この時点で、
script.DoString(...)
の呼び出しはファイルを実行し、グローバル環境にfact関数を...
そして、この行を導入しました。
DynValue res = script.Call(script.Globals["fact"], 4);
これは、スクリプトのグローバルからfact関数を取得し、4をパ...
もっと良い(つまり、パフォーマンスの良い)方法があります...
factの関数は何度でも呼び出せることに注意してください。Scr...
** DynValueのすべて [#w1153ae3]
- すべてはDynValueであり、DynValueである
DynValueの概念はMoonSharpの根幹にあり、これまではあまり触...
タイトルにもあるように、MoonSharpの(ほぼ)すべてがDynVal...
DynValueは、スクリプト内の値を表し、その型に関わらず、テ...
では、まず前回のチュートリアルの最後のステップから始めて...
*** ステップ1: 前回のチュートリアルで行ったことをすべてや...
再び、前回の最後のステップから始めます。やったよね?
リファレンスドキュメントはここで入手できます。
*** ステップ2: fact関数をDynValueで取得する [#j049e11e]
最初の変更点として、fact変数を別の方法で取得します。
double MoonSharpFactorial()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end";
Script script = new Script();
script.DoString(scriptCode);
DynValue luaFactFunction = script.Globals.Get("fact");
DynValue res = script.Call(luaFactFunction, 4);
return res.Number;
}
この行について少し説明しましょう。
DynValue luaFactFunction = script.Globals.Get("fact");
これは、スクリプトのグローバルからfact関数を取得します。
Getメソッドは、インデクサープロパティとは反対に、DynValue...
インデクサーは、代わりにSystem.Objectに変換しようとします。
この場合、DynValueに関心があるので、Getメソッドを使用しま...
*** ステップ3: 数値をDynValueで取得する [#afda98b8]
さて、もう1つの変換を避けることにも関心があるなら、Callメ...
ここでは必要ありませんが、他の場所では必要になるかもしれ...
double MoonSharpFactorial2()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n*fact(n - 1)
end
end";
Script script = new Script();
script.DoString(scriptCode);
DynValue luaFactFunction = script.Globals.Get("fact");
DynValue res = script.Call(luaFactFunction, DynValue.N...
return res.Number;
}
つまり、数値を以下のように置き換えました。
DynValue.NewNumber(4)
DynValueには、"New"で始まる多くのファクトリメソッドがあり...
これらを使用して、最初から値を作成できます。
また、便利なFromObjectメソッドもあります。これはオブジェ...
*** ステップ4: DataTypeの理解 [#vbad2568]
DynValueで最も重要なプロパティの1つはTypeです。
Typeプロパティは列挙型で、DynValueにどのような種類のデー...
DynValueに何が含まれているかを知りたい場合は、いつでもTyp...
// 新しい数値を作成
DynValue v1 = DynValue.NewNumber(1);
// 新しい文字列を作成
DynValue v2 = DynValue.NewString("ciao");
// 自動変換を使用して別の文字列を作成
DynValue v3 = DynValue.FromObject(new Script(), "hello");
// Number - String - String と表示される
Console.WriteLine("{0} - {1} - {2}", v1.Type, v2.Type, v...
// Number - String - 0になると期待すべきではないゴミの数...
Console.WriteLine("{0} - {1} - {2}", v1.Number, v2.Strin...
DynValueの一部のプロパティは、値が特定の型の場合にのみ意...
例えば、NumberプロパティはDataType.Numberの場合にのみ意味...
DynValueの中身が確実にわかっていない限り、そのプロパティ...
DynValueが特定の型を含んでいると想定しているのに、別の型...
*** ステップ5: タプル [#gddb0564]
ご存知のように(あるいは知っておくべきですが)、Luaでは関...
これを処理するために、特別なDynValue型(DataType.Tuple)...
これは聞こえるよりも簡単です。
DynValue ret = Script.RunString("return true, 'ciao', 2*...
// "Tuple" と表示される
Console.WriteLine("{0}", ret.Type);
// 以下が表示される:
// Boolean = true
// String = "ciao"
// Number = 6
for (int i = 0; i < ret.Tuple.Length; i++)
Console.WriteLine("{0} = {1}", ret.Tuple[i].Type, ret....
終わりに
DynValuesについて終わりです。
まだまだ学ぶべきことはたくさんありますが、このトピックを...
すべてがこれを中心に回っているので、これを肝に銘じておい...
** C#をコールバックする [#o1bf9b18]
- ..そしてF#、VB.NET、C++/CLI、Booなども
スクリプトは、アプリケーション自体に実装された構成要素か...
ビジネスアプリケーション、ビデオゲーム、またはある種のツ...
そして、手続き型プログラミングの基本的な構成要素は関数で...
*** 演習1、ステップ1: 階乗に飽きるな [#g99c9a42]
これまで使ってきた標準的な階乗スクリプトで基礎を押さえま...
private static double CallbackTest()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return n * fact(n - 1);
end
end";
Script script = new Script();
script.DoString(scriptCode);
DynValue res = script.Call(script.Globals["fact"], 4);
return res.Number;
}
*** 演習1、ステップ2: 乗算関数をカスタマイズする [#o01730...
さて、乗算をホストアプリケーションのAPI関数で実装したいと...
この場合、そうする目的はありませんが、学ぶためにここにい...
private static int Mul(int a, int b)
{
return a * b;
}
private static double CallbackTest()
{
string scriptCode = @"
-- 階乗関数を定義
function fact (n)
if (n == 0) then
return 1
else
return Mul(n, fact(n - 1));
end
end";
Script script = new Script();
script.Globals["Mul"] = (Func<int, int, int>)Mul;
script.DoString(scriptCode);
DynValue res = script.Call(script.Globals["fact"], 4);
return res.Number;
}
それだけです!
script.Globals["Mul"] = (Func<int, int, int>)Mul;
これにより、グローバル環境のMul変数が、アプリケーションの...
ここでは、C#コンパイラを満足させるために、デリゲートをFun...
デリゲートをSystem.Objectにキャストするために使用する方法...
また、メソッドをstaticに定義しましたが、この場合、それら...
インスタンスメソッドも問題ありません。
*** 演習2: 数値のシーケンスを返す [#ved358ee]
問題: 整数のシーケンスを返すAPI関数を用意する。スクリプト...
private static IEnumerable<int> GetNumbers()
{
for (int i = 1; i <= 10; i++)
yield return i;
}
private static double EnumerableTest()
{
string scriptCode = @"
total = 0;
for i in getNumbers() do
total = total + i;
end
return total;
";
Script script = new Script();
script.Globals["getNumbers"] = (Func<IEnumerable<int...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ここでも、特に難しいことはありません。
IEnumerable(またはIEnumerator)が、スクリプトを実行する...
スクリプトには直接実行可能なコードが含まれているため、Cal...
これを覚えておいてください。
DoStringとDoFileは、スクリプトに含まれるコードを即座に実...
注意すべき点が1つあります。MoonSharpは、System.Collection...
つまり、ジェネリックではないバリアントです。
何らかの理由でジェネリックイテレータを実装する際にジェネ...
上記のように、すべての標準コレクション型とイテレータメソ...
*** テーブルを返す [#me086187]
問題: 今度は整数のシーケンスをテーブルで返すAPI関数を用意...
private static List<int> GetNumberList()
{
List<int> lst = new List<int>();
for (int i = 1; i <= 10; i++)
lst.Add(i);
return lst;
}
private static double TableTest1()
{
string scriptCode = @"
total = 0;
tbl = getNumbers()
for _, i in ipairs(tbl) do
total = total + i;
end
return total;
";
Script script = new Script();
script.Globals["getNumbers"] = (Func<List<int>>)GetN...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ここでは、List<int>がLuaテーブルに自動的に変換される様子...
結果のテーブルは、Luaテーブルが通常そうであるように、1か...
ただし、もっと良い方法があります。
関数内で直接Luaテーブルを構築することができます。
private static Table GetNumberTable(Script script)
{
Table tbl = new Table(script);
for (int i = 1; i <= 10; i++)
tbl[i] = i;
return tbl;
}
private static double TableTest2()
{
string scriptCode = @"
total = 0;
tbl = getNumbers()
for _, i in ipairs(tbl) do
total = total + i;
end
return total;
";
Script script = new Script();
script.Globals["getNumbers"] = (Func<Script, Table>)...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
Tableオブジェクトを使用してテーブルを操作するのがいかに簡...
ただし、注意すべき点が2つあります。
新しいTableオブジェクトを作成するには、実行中のスクリプト...
CLR関数にScriptパラメータがあり、それがLuaスクリプトで利...
これは、(このように使用される可能性は低いですが)ScriptE...
これらが何をするのかわからなくても心配しないでください。
MoonSharpの基本を理解するのに必要ありません!
良い習慣として、可能な限りScriptオブジェクトを保持するよ...
(テーブルの作成など)Scriptオブジェクトを使用してのみ実...
*** テーブルを受け入れる [#p43434d6]
テーブルは自動的にList<T>に変換されます。
例えば、
public static double TableTestReverse()
{
string scriptCode = @"
return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
";
Script script = new Script();
script.Globals["dosum"] = (Func<List<int>, int>)(l => l...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ただし、これによって一部のプラットフォーム(具体的にはiOS...
この問題を回避する方法はたくさんありますが(他のチュート...
public static double TableTestReverseSafer()
{
string scriptCode = @"
return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
";
Script script = new Script();
script.Globals["dosum"] = (Func<List<object>, int>)(l =...
DynValue res = script.DoString(scriptCode);
return res.Number;
}
さらに高速な別の方法は、Tableオブジェクトを使用することで...
static double Sum(Table t)
{
var nums = from v in t.Values
where v.Type == DataType.Number
select v.Number;
return nums.Sum();
}
private static double TableTestReverseWithTable()
{
string scriptCode = @"
return dosum { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
";
Script script = new Script();
script.Globals["dosum"] = (Func<Table, double>)Sum;
DynValue res = script.DoString(scriptCode);
return res.Number;
}
しかし、ここではDynValue(s)を扱う必要があります。
これらすべてを理解するには、MoonSharpがLuaの型をC#の型に...
次の部分で説明します。
** 自動変換の説明 [#zdd8f29e]
- ..今回はコードなし
MoonSharpとCLRの統合についてさらに掘り下げる前に、型がど...
残念ながら、逆方向は順方向とは大きく異なるので、2つを別々...
これは少し複雑すぎませんか? - あなたはそう尋ねるかもしれ...
確かにそうです。
自動的なものは良いですが、失敗すると、ひどく複雑な方法で...
2つの方法があります:DynValueをそのまま使用するか、カスタ...
これらの解決策は、正気と単純さを得るだけでなく、自動変換...
*** カスタムコンバーター [#iaa65800]
変換プロセスをカスタマイズすることは可能ですが、設定はグ...
変換をカスタマイズするには、
Script.GlobalOptions.CustomConverters
の適切なコールバックを設定するだけです。
例えば、CLRからスクリプトへの変換が行われるときに、すべての
StringBuilder
オブジェクトを大文字の文字列に変換したい場合は、次のよう...
Script.GlobalOptions.CustomConverters.SetClrToScriptCust...
v => DynValue.NewString(v.ToString().ToUpper()));
テーブルがIList<int>に一致する必要がある場合に、テーブル...
Script.GlobalOptions.CustomConverters.SetScriptToClrCust...
v => new List<int>() { ... });
コンバーターがnullを返した場合、システムはカスタムコンバ...
*** CLR型からMoonSharp型への自動変換 [#y6c7cab4]
この変換は、次の状況で適用されます。
- スクリプトによって呼び出された関数からオブジェクトを返...
- ユーザーデータのプロパティからオブジェクトを返すとき
- インデックス演算子を使用してテーブルに値を設定するとき
- DynValue.FromObjectを呼び出すとき
- DynValueの代わりにSystem.Objectを取る関数のオーバーロー...
この変換は実際にはかなり簡単です。次の表は、変換を説明し...
| CLR型 | C#のわかりやす...
|----------------------------------------|---------------...
| void | ...
| null | ...
| MoonSharp.Interpreter.DynValue | ...
| System.SByte | sbyte ...
| System.Byte | byte ...
| System.Int16 | short ...
| System.UInt16 | ushort ...
| System.Int32 | int ...
| System.UInt32 | uint ...
| System.Int64 | long ...
| System.UInt64 | ulong ...
| System.Single | float ...
| System.Decimal | decimal ...
| System.Double | double ...
| System.Boolean | bool ...
| System.String | string ...
| System.Text.StringBuilder | ...
| System.Char | char ...
| MoonSharp.Interpreter.Table | ...
| MoonSharp.Interpreter.CallbackFunction | ...
| System.Delegate | ...
| System.Object | object ...
| System.Type | ...
| MoonSharp.Interpreter.Closure | ...
| System.Reflection.MethodInfo | ...
| System.Collections.IList | ...
| System.Collections.IDictionary | ...
| System.Collections.IEnumerable | ...
| System.Collections.IEnumerator | ...
これには、コレクションのかなり良いカバレッジが含まれてい...
独自のコレクションを書く場合は、これらの非ジェネリックイ...
このロジックを使用して変換できない値はすべて、ScriptRunti...
*** MoonSharp型からCLR型への標準の自動変換 [#b443915a]
反対の変換はかなり複雑です。
実際、2つの異なる変換パスがあります。
「標準」の変換パスと、「制約付き」の変換パスです。
最初の変換パスは、実際に何を受け取りたいかを指定せずにDyn...
これは以下の場合に使用されます。
- DynValue.ToObjectを呼び出すとき
- インデクサーを使用してテーブルから値を取得するとき
- 制約付き変換の特定のサブケース(下記参照)
ここでは、デフォルトの変換を見ていきます。実際には簡単で...
| MoonSharp型 | CLR型 ...
|----------------------------------------|---------------...
| nil | null ...
| boolean | System.Boolean...
| number | System.Double ...
| string | System.String ...
| function | MoonSharp.Inte...
| function | MoonSharp.Inte...
| table | MoonSharp.Inte...
| tuple | MoonSharp.Inte...
| userdata | (special) ...
このロジックを使用して変換できない値はすべて、ScriptRunti...
*** MoonSharp型からCLR型への制約付き自動変換 [#b3fb4110]
しかし、制約付き自動変換ははるかに複雑です。この場合、Moo...
これは以下の場合に使用されます。
- DynValue.ToObject<T>を呼び出すとき
- CLR関数呼び出しやプロパティ設定でスクリプト値をパラメー...
MoonSharpは値の変換に非常に努力しますが、特にテーブルが関...
この場合、変換は単純なマッピングのテーブルではなく、プロ...
*** 特殊なケース [#h25b1ae1]
- ターゲットがMoonSharp.Interpreter.DynValue型の場合は変...
- ターゲットがSystem.Object型の場合は、前述のデフォルトの...
- マッピングされるnil値の場合、nullは参照型とnullable値型...
- 値が提供されていない場合は、可能であればデフォルト値が...
*** 文字列 [#gde47277]
文字列は、System.String、System.Text.StringBuilder、Syste...
*** ブール値 [#lb1bcc8c]
ブール値は、System.BooleanやSystem.Nullable<System.Boolea...
*** 数値 [#dc22c32c]
数値は、System.SByte、System.Byte、System.Int16、System.U...
*** 関数 [#z9738d47]
スクリプト関数は、MoonSharp.Interpreter.ClosureまたはMoon...
*** ユーザーデータ [#jbe4344d]
ユーザーデータは、「静的」でない場合にのみ変換されます(...
また、オブジェクトのToString()メソッドを呼び出すことで、S...
*** テーブル [#g19e08d9]
テーブルは以下に変換できます。
- MoonSharp.Interpreter.Table - もちろん
- Dictionary<DynValue, DynValue>から割り当て可能な型。
- Dictionary<object, object>から割り当て可能な型。キーと...
- List<DynValue>から割り当て可能な型。
- List<object>から割り当て可能な型。要素は、デフォルトの...
- DynValue[]から割り当て可能な型。
- object[]から割り当て可能な型。要素は、デフォルトのマッ...
- T[]、IList<T>、List<T>、ICollection<T>、IEnumerable<T>...
- IDictionary<K,V>、Dictionary<K,V>。ここで、KとVは変換可...
ジェネリックや型付き配列への変換には、次の制限があること...
- リフレクションを使用して実行時に型が作成されるため、速...
- アイテムの型が値型の場合、iOSやAOTモードで実行される他...
これらの問題を補うために、開発の後半でカスタムコンバータ...
一部の変換(List<int>への変換など)は、Unity/iOSなどのAOT...
iOSなどのAOTプラットフォームをターゲットにする場合は、値...
** オブジェクトの共有 [#obbc6f3a]
- LuaとC#はお互いに話す
注:このページに記載されている一部の機能は、masterブラン...
MoonSharpの便利な機能の1つは、.NETオブジェクトをスクリプ...
デフォルトでは、型はすべてのパブリックメソッド、パブリッ...
MoonSharpVisibleアトリビュートを使用して、このデフォルト...
CLRコードとスクリプトコード間のインターフェイスとして専用...
多くのデザインパターン(アダプター、ファサード、プロキシ...
これは特に以下のために重要です。
- スクリプトができること、できないことを制限する(セキュ...
- スクリプト作成者にとって意味のあるインターフェイスを提...
- インターフェイスを別々に文書化する
- スクリプトを破ることなく、内部ロジックとモデルを変更で...
これらの理由から、MoonSharpはデフォルトで、スクリプトで使...
スクリプトを信頼できるシナリオでは、`
UserData.RegistrationPolicy = InteropRegistrationPolicy....
を使用して自動登録をグローバルに有効にできます。
危険なので、警告しておきます。
*** メニューにあるもの [#dda0ae94]
では、メニューにあるものを見てみましょう。
- まず、型記述子について説明しましょう - 舞台裏で何が起こ...
- シンプルに保つ - 始めるための最も簡単な方法
- 少し複雑 - 少し複雑さと詳細を加えて掘り下げる
- 静的メンバーの呼び出し - 静的メンバーを呼び出す方法
- ':' と '.' のどちらを使うべきか - メソッドの呼び出し方...
- オーバーロード - オーバーロードがどのように処理されるか
- ByRefパラメーター(C#のref/out) - ref/outパラメーター...
- インデクサー - インデクサーの処理方法
- ユーザーデータ上の演算子とメタメソッド - 演算子のオーバ...
- 拡張メソッド - 拡張メソッドの使用方法
- イベント - イベントの使用方法
- インターオペラビリティアクセスモード - インターオペラビ...
- MoonSharpHiddenとMoonSharpVisibleによる可視性の変更 - ...
- メンバーの削除 - メンバーの可視性を削除する方法
たくさんありますね。では、始めましょう。
*** 型記述子 [#ce23a6ed]
まず、型記述子について説明しましょう
最初に、インターオペラビリティがどのように実装されている...
すべてのCLR型は、CLR型をスクリプトに記述する役割を持つ「...
型をインターオペラビリティ用に登録するとは、型を記述子(M...
この記述子は、メソッド、プロパティなどのディスパッチに使...
次のセクション以降では、MoonSharpが提供する「自動」記述子...
*** 独自の記述子を実装したい場合 [#i28f4d6d]
独自の記述子を実装したい場合(簡単ではなく、必要でない限...
- 独自の型を記述するためのアドホックなIUserDataDescriptor...
- 型にIUserDataTypeインターフェイスを実装させる。これは簡...
- StandardUserDataDescriptorを拡張または埋め込み、必要な...
記述子の作成を助けるために、次のクラスが利用できます。
- StandardUserDataDescriptor - これはMoonSharpが実装する...
- StandardUserDataMethodDescriptor - これは単一のメソッド...
- StandardUserDataOverloadedMethodDescriptor - これはオー...
- StandardUserDataPropertyDescriptor - これは単一のプロパ...
- StandardUserDataFieldDescriptor - これは単一のフィール...
*** ユーザーデータとしての値型とのインターオペラビリティ...
値型をパラメーターとして渡す関数を呼び出す場合と同様に、...
繰り返しになりますが、これは値型の標準的な動作と変わりま...
さらに、値型は参照型ほどの最適化の範囲をサポートしていな...
*** シンプルに保つ [#b3bac791]
では、最初の例を見てみましょう。
[MoonSharpUserData]
class MyClass
{
public double calcHypotenuse(double a, double b)
{
return Math.Sqrt(a * a + b * b);
}
}
double CallMyClass1()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// MoonSharpUserData型をすべて自動的に登録
UserData.RegisterAssembly();
Script script = new Script();
// MyClassのインスタンスをスクリプトのグローバルに渡す
script.Globals["obj"] = new MyClass();
DynValue res = script.DoString(scriptCode);
return res.Number;
}
ここでは以下のことを行っています。
- [MoonSharpUserData]アトリビュートを持つクラスを定義
- MyClassオブジェクトのインスタンスをスクリプトのグローバ...
- スクリプトからMyClassのメソッドを呼び出す。コールバック...
*** 少し複雑 [#x8b60ac6]
もう少し複雑な例を試してみましょう。
class MyClass
{
public double CalcHypotenuse(double a, double b)
{
return Math.Sqrt(a * a + b * b);
}
}
static double CallMyClass2()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// MyClassだけを明示的に登録
UserData.RegisterType<MyClass>();
Script script = new Script();
// ユーザーデータを明示的に作成
DynValue obj = UserData.Create(new MyClass());
script.Globals.Set("obj", obj);
DynValue res = script.DoString(scriptCode);
return res.Number;
}
*** 大きな違い [#a756817e]
大きな違いは以下の通りです。
- [MoonSharpUserData]アトリビュートはありません。もう必要...
- RegisterAssemblyの代わりに、RegisterTypeを呼び出して特...
- ユーザーデータのDynValueを明示的に作成します。
また、C#コードではメソッドがCalcHypotenuse と呼ばれていま...
他のバージョンが存在しない限り、MoonSharpは異なる言語の構...
*** 静的メンバーの呼び出し [#b88a2ae1]
calcHypotenuse メソッドが静的であるとしましょう。
[MoonSharpUserData]
class MyClassStatic
{
public static double calcHypotenuse(double a, double...
{
return Math.Sqrt(a * a + b * b);
}
}
*** 呼び出す方法 [#x240cc3a]
これを呼び出すには2つの方法があります。
*** 方法1 - 静的メソッドはインスタンスから透過的に呼び出...
double MyClassStaticThroughInstance()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// MoonSharpUserData型をすべて自動的に登録
UserData.RegisterAssembly();
Script script = new Script();
script.Globals["obj"] = new MyClassStatic();
DynValue res = script.DoString(scriptCode);
return res.Number;
}
*** 別の方法 [#of33f4f5]
- 型を直接渡す(またはUserData.CreateStaticメソッドを使...
double MyClassStaticThroughPlaceholder()
{
string scriptCode = @"
return obj.calcHypotenuse(3, 4);
";
// MoonSharpUserData型をすべて自動的に登録
UserData.RegisterAssembly();
Script script = new Script();
script.Globals["obj"] = typeof(MyClassStatic);
DynValue res = script.DoString(scriptCode);
return res.Number;
}
':' と '.' のどちらを使うべきか
上記の例のコードを考えると、この構文を使うべきでしょうか
return obj.calcHypotenuse(3, 4);
それともこちらでしょうか?
return obj:calcHypotenuse(3, 4);
99.999%の場合、違いはありません。MoonSharpは、ユーザーデ...
*** 違いが出る可能性があるコーナーケース [#r13135cc]
違いが出る可能性があるコーナーケースがあります。たとえば...
*** オーバーロード [#v6fea100]
オーバーロードされたメソッドがサポートされています。オー...
これは、いくつかの曖昧さが存在するためです。たとえば、オ...
void DoSomething(int i) { ... }
void DoSomething(float f) { ... }
Luaのすべての数値がdoubleであることを考えると、MoonSharp...
この問題を解決するために、MoonSharpは入力型に対するすべて...
MoonSharpは、ヒューリスティックの重みを可能な限り安定させ...
とは言え、MoonSharpが考えているのとは異なるオーバーロード...
そのため、オーバーロードが同等の処理を行うようにすること...
- ByRefパラメーター(C#のref/out)
- ByRefメソッドパラメーター
* 参考 [#l6580144]
** MoonSharpによるUnityとLuaの連携 [#r91a70b3]
https://qiita.com/massu2357/items/425cc93b5965ceea29aa
ページ名: