赞
踩
function id(...)
return ...
end
function add(a, b) return a + b end
function array_exchange(arr)
arr[0], arr[1] = arr[1], arr[0]
end
local v3 = CS.UnityEngine.Vector3(7, 8, 9)
local vt = CS.XLuaTest.MyStruct(5, 6)
function lua_access_csharp()
monoBehaviour:FloatParamMethod(123) --primitive
monoBehaviour:Vector3ParamMethod(v3) --vector3
local rnd = math.random(1, 100)
local r = monoBehaviour:Vector3ParamMethod({x = 1, y = 2, z = rnd}) --vector3
assert(r.x == 1 and r.y == 2 and r.z == rnd)
monoBehaviour:StructParamMethod(vt) --custom struct
r = monoBehaviour:StructParamMethod({a = 1, b = rnd, e = {c = rnd}})
assert(r.b == rnd and r.e.c == rnd)
monoBehaviour:EnumParamMethod(CS.XLuaTest.MyEnum.E2) --enum
monoBehaviour:DecimalParamMethod(monoBehaviour.a5[0])
monoBehaviour.a1[0], monoBehaviour.a1[1] = monoBehaviour.a1[1], monoBehaviour.a1[0] -- field
end
exchanger = {
exchange = function(self, arr)
array_exchange(arr)
end
}
A = { B = { C = 789}}
GDATA = 1234;
解释
这段代码是Lua脚本的示例,结合了与C#交互的一些功能。让我们逐个解释:
函数 id(...)
和 add(a, b)
:
id(...)
函数是一个不定参数的函数,它返回接收到的所有参数。add(a, b)
函数简单地计算两个参数的和并返回结果。该这两个函数的目的是要测试让数据从C#传入lua再传回C#,观察gc情况
函数 array_exchange(arr)
:
arr
的第一个和第二个元素的位置。Lua中的数组索引从1开始,因此 arr[0]
实际上是 arr[1]
,arr[1]
是 arr[2]
。该函数利用了lua的等号特性,本质是一个swap函数,并且只交换arr的头两个数据
定义了两个变量 v3
和 vt
:
v3
是一个使用C#的Unity引擎的 Vector3
结构体,表示一个三维向量 (7, 8, 9)。vt
是一个自定义的结构体 MyStruct
的实例,其中包含字段 (5, 6)。函数 lua_access_csharp()
:
monoBehaviour:FloatParamMethod(123)
调用了一个接受单精度浮点数参数的方法。monoBehaviour:Vector3ParamMethod(v3)
传递了一个 Vector3
类型的参数给一个接受 Vector3
的方法。math.random(1, 100)
生成一个随机数 rnd
,然后传递给一个接受 Vector3
参数的方法,并验证返回的结果。monoBehaviour:StructParamMethod(vt)
传递了一个自定义结构体类型的参数。monoBehaviour:EnumParamMethod(CS.XLuaTest.MyEnum.E2)
传递了一个枚举类型的参数。monoBehaviour:DecimalParamMethod(monoBehaviour.a5[0])
传递了一个十进制数参数。monoBehaviour.a1
的两个元素的位置。monoBehaviour是在C#中set的变量,即this,所以这里是在使用C#函数处理lua对象
变量 exchanger
:
exchanger
是一个包含 exchange
方法的表,该方法接受一个数组参数并调用 array_exchange
函数来交换数组的两个元素。该表在C#中创建有对应函数的接口获取,通过C#的接口调用其方法
全局变量 A
和 GDATA
:
A
是一个嵌套表结构,其中包含 B
字段,B
字段包含 C
字段。GDATA
是一个全局变量,存储整数值 1234。 这两个变量会在C#中每次取出,并且 + 1放回
[GCOptimize]
[LuaCallCSharp]
public struct Pedding
{
public byte c;
}
[GCOptimize]
[LuaCallCSharp]
public struct MyStruct
{
public int a;
public int b;
public decimal c;
public Pedding e;
}
[LuaCallCSharp]
public enum MyEnum
{
E1,
E2
}
使用GCOptimize优化只有值类型的Struct以及嵌套Struct
使用LuaCallCSharp指示Lua可以调用这些Struct
[CSharpCallLua]
public delegate int IntParam(int p);
[CSharpCallLua]
public delegate Vector3 Vector3Param(Vector3 p);
[CSharpCallLua]
public delegate MyStruct CustomValueTypeParam(MyStruct p);
[CSharpCallLua]
public delegate MyEnum EnumParam(MyEnum p);
[CSharpCallLua]
public delegate decimal DecimalParam(decimal p);
[CSharpCallLua]
public delegate void ArrayAccess(Array arr);
[CSharpCallLua]
public interface IExchanger
{
void exchange(Array arr);
}
创建一系列delegate接收Lua函数,以及一个接口接收lua的表
以上都是类外的前期声明准备,接下来是在类中的字段定义
首先最重要的一点是,类要加上LuaCallCSharp的标签,因为后面会在里面向Lua传入自己的this指针,因此lua是可以调用类的
在类中,先定义一些等会要用到的妙妙工具(字段)
IntParam f1;
Vector3Param f2;
CustomValueTypeParam f3;
EnumParam f4;
DecimalParam f5;
ArrayAccess farr;
Action flua;
IExchanger ie;
LuaFunction add;
[NonSerialized]
public double[] a1 = new double[] { 1, 2 };
[NonSerialized]
public Vector3[] a2 = new Vector3[] { new Vector3(1, 2, 3), new Vector3(4, 5, 6) };
[NonSerialized]
public MyStruct[] a3 = new MyStruct[] { new MyStruct(1, 2), new MyStruct(3, 4) };
[NonSerialized]
public MyEnum[] a4 = new MyEnum[] { MyEnum.E1, MyEnum.E2 };
[NonSerialized]
public decimal[] a5 = new decimal[] { 1.00001M, 2.00002M };
前五个委托接收Lua的id函数,不同的值类型数据都测了一遍(从C#传lua再传回来)
farr接收lua的交换函数,传入数组,交换数组头两个元素,再传回来
flua接收lua_access_csharp()函数,负责触发lua去访问c#的变量和函数
ie传入表exchanger,并通过里面的函数去访问交换函数(同2)
add是用LuaFunction对象创建的,可以通过add.Func<int, int, int>(34, 56); // LuaFunction.Func<T1, T2, TResult> 的方式访问。
后面的a1 ~ a5则是为交换函数准备的不同类型的数组
luaenv.DoString(script);
luaenv.Global.Set("monoBehaviour", this);
luaenv.Global.Get("id", out f1);
luaenv.Global.Get("id", out f2);
luaenv.Global.Get("id", out f3);
luaenv.Global.Get("id", out f4);
luaenv.Global.Get("id", out f5);
luaenv.Global.Get("array_exchange", out farr);
luaenv.Global.Get("lua_access_csharp", out flua);
luaenv.Global.Get("exchanger", out ie);
luaenv.Global.Get("add", out add);
luaenv.Global.Set("g_int", 123);
luaenv.Global.Set(123, 456);
int i;
luaenv.Global.Get("g_int", out i);
Debug.Log("g_int:" + i);
luaenv.Global.Get(123, out i);
Debug.Log("123:" + i);
接下来先在luaenv中运行脚本,再将对应的值提取到C#字段中,具体对应关系上一段已经说了
// c# call lua function with value type but no gc (using delegate)
//仅仅传递数值再返回C#中
f1(1); // primitive type
f2(new Vector3(1, 2, 3)); // vector3
MyStruct mystruct1 = new MyStruct(5, 6);
f3(mystruct1); // custom complex value type
f4(MyEnum.E1); //enum
decimal dec1 = -32132143143100109.00010001010M;
f5(dec1); //decimal
// using LuaFunction.Func<T1, T2, TResult>
//使用LuaFunction风格的函数触发
add.Func<int, int, int>(34, 56); // LuaFunction.Func<T1, T2, TResult>
// lua access c# value type array no gc
//传递数组进去并交换头两个数的位置再传回来
farr(a1); //primitive value type array
farr(a2); //vector3 array
farr(a3); //custom struct array
farr(a4); //enum arry
farr(a5); //decimal arry
// lua call c# no gc with value type
//让lua侧调用C#变量
flua();
//c# call lua using interface
//使用接口风格调用表中的交换数组头两个元素的函数
ie.exchange(a2);
//no gc LuaTable use
//直接设置获取lua中的值的数
luaenv.Global.Set("g_int", 456);
int i;
luaenv.Global.Get("g_int", out i);
luaenv.Global.Set(123.0001, mystruct1);
MyStruct mystruct2;
luaenv.Global.Get(123.0001, out mystruct2);
decimal dec2 = 0.0000001M;
luaenv.Global.Set((byte)12, dec1);
luaenv.Global.Get((byte)12, out dec2);
//这两个是lua中定义的值和嵌套表,访问和修改其也不会产生gc
int gdata = luaenv.Global.Get<int>("GDATA");
luaenv.Global.SetInPath("GDATA", gdata + 1);
int abc = luaenv.Global.GetInPath<int>("A.B.C");
luaenv.Global.SetInPath("A.B.C", abc + 1);
//lua手动gc函数
luaenv.Tick();
这一段代码是Update中的,会每帧执行,主要是展示大量传递数据下不会产生gc alloc
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。