|
文章目录
一 Hello World例子 执行字符串二 执行lua文件,C#与lua交互三 UI绑定与交互四 通过元表,实现lua面向对象五 NoGC Lua访问C#函数无gc
一 Hello World例子 执行字符串
- namespaceXLuaTest{publicclassHelloworld:MonoBehaviour{voidStart(){LuaEnv luaenv =newLuaEnv();
- luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");
- luaenv.Dispose();}}}
复制代码 最基本是直接用LuaEnv.DoString执行一个字符串,当然,字符串得符合Lua语法
二 执行lua文件,C#与lua交互
C#文件 LuaBehaviour.cs- namespaceXLuaTest{[System.Serializable]publicclassInjection{publicstring name;publicGameObjectvalue;}//xLua用白名单来指明生成哪些代码,而白名单通过attribute来配置//比如你想从lua调用c#的某个类,希望生成适配代码//你可以为这个类型打一个LuaCallCSharp标签[LuaCallCSharp]publicclassLuaBehaviour:MonoBehaviour{publicTextAsset luaScript;publicInjection[] injections;//所有lua共享这一个luaenv!internalstaticLuaEnv luaEnv =newLuaEnv();internalstaticfloat lastGCTime =0;internalconstfloat GCInterval =1;//1 second privateAction luaStart;privateAction luaUpdate;privateAction luaOnDestroy;privateLuaTable scriptEnv;voidAwake(){
- scriptEnv = luaEnv.NewTable();// 为每个脚本设置一个独立的环境// 可一定程度上防止脚本间全局变量、函数冲突LuaTable meta = luaEnv.NewTable();
- meta.Set("__index", luaEnv.Global);
- scriptEnv.SetMetaTable(meta);
- meta.Dispose();//设置lua中self为当前C#中的this,方便对当前对象进行操作
- scriptEnv.Set("self",this);//设置lua中通过name来获取GameObjectforeach(var injection in injections){
- scriptEnv.Set(injection.name, injection.value);}// 加载luaScript变量上挂载的lua,别名为LuaTestScript// 加载到scriptEnv表中
- luaEnv.DoString(luaScript.text,"LuaTestScript", scriptEnv);// C#访问lua中的方法// 注意:通常是用luaenv.Global.Get访问全局方法// 这里是之前设置了元表,meta.Set("__index", luaEnv.Global);Action luaAwake = scriptEnv.Get<Action>("awake");
- scriptEnv.Get("start",out luaStart);
- scriptEnv.Get("update",out luaUpdate);
- scriptEnv.Get("ondestroy",out luaOnDestroy);if(luaAwake !=null){luaAwake();}}// Use this for initializationvoidStart(){if(luaStart !=null){luaStart();}}// Update is called once per framevoidUpdate(){if(luaUpdate !=null){luaUpdate();}if(Time.time - LuaBehaviour.lastGCTime > GCInterval){
- luaEnv.Tick();
- LuaBehaviour.lastGCTime = Time.time;}}voidOnDestroy(){if(luaOnDestroy !=null){luaOnDestroy();}
- luaOnDestroy =null;
- luaUpdate =null;
- luaStart =null;
- scriptEnv.Dispose();
- injections =null;}}
复制代码 lua文件 LuaTestScript.lua- local speed =10local lightCpnt =nilfunctionstart()print("lua start...")** 这里lightObject是C#中Injection类通过name来访问GameObject
- ** 简单理解成Unity中组件挂载的GameObject,灯光
- print("injected object", lightObject)
- lightCpnt= lightObject:GetComponent(typeof(CS.UnityEngine.Light))endfunctionupdate()local r = CS.UnityEngine.Vector3.up * CS.UnityEngine.Time.deltaTime * speed
- ** self表示LuaBehaviour.cs中的this,也就是挂载脚本那个对象Cube
- self.transform:Rotate(r)
- lightCpnt.color = CS.UnityEngine.Color(CS.UnityEngine.Mathf.Sin(CS.UnityEngine.Time.time)/2+0.5,0,0,1)endfunctionondestroy()print("lua destroy")end
复制代码 Unity中的情况
三 UI绑定与交互
C# 同上LuaBehaviour.cs文件
Lua文件 ButtonInteraction.lua- functionstart()print("lua start...")** 这里的self就是LuaBehaviour组件本身this
- ** 获得Button组件,对onClick注册监听方法
- ** input是注入器绑定的对象,即InputField对象
- ** 这里功能是对按钮注册一个匿名函数,当点击按钮时候,回调匿名函数
- ** 匿名函数是输出输入框中的文本
- self:GetComponent("Button").onClick:AddListener(function()print("clicked, you input is '"..input:GetComponent("InputField").text .."'")end)end
复制代码 Unity中的情况
四 通过元表,实现lua面向对象
C# InvokeLua.cs- namespaceXLuaTest{//EventArgs是自定义事件类//PropertyChangedEventArgs用于做属性改变事件publicclassPropertyChangedEventArgs:EventArgs{publicstring name;publicobjectvalue;}publicclassInvokeLua:MonoBehaviour{[CSharpCallLua]//定义一个接口,里面声明PropertyChangedEventArgs事件publicinterfaceICalc{//定义一个PropertyChangedEventArgs类型的事件eventEventHandler<PropertyChangedEventArgs> PropertyChanged;intAdd(int a,int b);int Mult {get;set;}objectthis[int index]{get;set;}}[CSharpCallLua]//定义一个接口类型的委托CalcNewpublicdelegateICalcCalcNew(int mult,paramsstring[] args);//字符串---实际上是lua代码privatestring script =@"
- *局部 表calc_mt 实际是下面构建一个表A的元表M
- * 元表M的元方法__index是一个表I
- * 用于模拟面向对象的
- * 当我们构建的表A这种寻找一个变量(方法)时候
- * (1)首先去表找,找的到则返回,若找不到继续下一步
- * (2)判断表是否有元表,若没有返回nil,若有继续下一步
- * (3)判断元表中是否有元方法__index,若元方法为nil,则返回nil
- * 若元方法存在,则判断元方法__index是函数还是一个表
- * 若元方法是一个函数,则返回函数值
- * 若元方法是一个表,则将该表作为目标重复(1)(2)(3)
- * 提示,这里将元表M的元方法__index设为一个表,表里面有许多方法,例如Add
- local calc_mt = {
- __index = {
- Add = function(self, a, b)
- return (a + b) * self.Mult
- end,
- get_Item = function(self, index)
- return self.list[index + 1]
- end,
- set_Item = function(self, index, value)
- self.list[index + 1] = value
- self:notify({name = index, value = value})
- end,
- add_PropertyChanged = function(self, delegate)
- if self.notifylist == nil then
- self.notifylist = {}
- end
- table.insert(self.notifylist, delegate)
- print('add',delegate)
- end,
- remove_PropertyChanged = function(self, delegate)
- for i=1, #self.notifylist do
- if CS.System.Object.Equals(self.notifylist[i], delegate) then
- table.remove(self.notifylist, i)
- break
- end
- end
- print('remove', delegate)
- end,
- notify = function(self, evt)
- if self.notifylist ~= nil then
- for i=1, #self.notifylist do
- self.notifylist[i](self, evt)
- end
- end
- end,
- }
- }
- * 新建一个表Calc,相关于类,继承与calc_mt
- * 定义一个全局表,增加一个叫做New的函数
- * New函数返回一个元表,将calc_mt设置为{}表的元表
- * {}中函数将mult赋值给Mult,带一个list表
- Calc = {
- * New可以理解成构造函数
- New = function (mult, ...)
- print(...)
- return setmetatable({Mult = mult, list = {'aaaa','bbbb','cccc'}}, calc_mt)
- * 等同于一下写法
- * local a = {Mult = mult, list = {'aaaa','bbbb','cccc'}}
- * local b = setmetatable(a, calc_mt)
- * return b
- end
- }
- ";// Use this for initializationvoidStart(){LuaEnv luaenv =newLuaEnv();Test(luaenv);//调用了带可变参数的delegate,函数结束都不会释放delegate,即使置空并调用GC
- luaenv.Dispose();}voidTest(LuaEnv luaenv){//读取lua代码
- luaenv.DoString(script);//luaenv.Global.GetInPath用于获取Lua中的方法//获得CalcNew的构造函数的引用,并映射到CalcNew委托上CalcNew calc_new = luaenv.Global.GetInPath<CalcNew>("Calc.New");//创建一个Calc的lua对象,并映射到CS上ICalc接口//calc_new(10, "hi", "john")等价于Calc.New(10, "hi", "john")//Mult = mult = 10, ... == "hi", "john"ICalc calc =calc_new(10,"hi","john");//constructor//调用lua元表的表I中Add方法//输出 (1+2)*10 = 30
- Debug.Log("sum(*10) ="+ calc.Add(1,2));
- calc.Mult =100;//输出 (1+2)*100 = 30
- Debug.Log("sum(*100)="+ calc.Add(1,2));//索引操作会用到get_Item和set_Item//在lua中索引是从1开始//在C#中索引是从0开始,这里是C#
- Debug.Log("list[0]="+ calc[0]);
- Debug.Log("list[1]="+ calc[1]);//委托绑定方法Notify
- calc.PropertyChanged += Notify;
- calc[1]="dddd";
- Debug.Log("list[1]="+ calc[1]);
- calc.PropertyChanged -= Notify;
- calc[1]="eeee";
- Debug.Log("list[1]="+ calc[1]);}voidNotify(object sender,PropertyChangedEventArgs e){
- Debug.Log(string.Format("{0} has property changed {1}={2}", sender, e.name, e.value));}// Update is called once per framevoidUpdate(){}}
复制代码 五 NoGC Lua访问C#函数无gc
C# NoGc.cs
[LuaCallCSharp] lua调用C#
[CSharpCallLua] C#调用lua
[GCOptimize] C#纯值类型
- namespace XLuaTest{[GCOptimize][LuaCallCSharp]
- public struct Pedding{
- public byte c;}[GCOptimize][LuaCallCSharp]
- public struct MyStruct{
- public MyStruct(int p1, int p2){
- a = p1;
- b = p2;
- c = p2;
- e.c =(byte)p1;}
- public int a;
- public int b;
- public decimal c;
- public Pedding e;}[LuaCallCSharp]
- public enum MyEnum{
- E1,
- E2
- }[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);}[LuaCallCSharp]
- public class NoGc :MonoBehaviour{
- LuaEnv luaenv = new LuaEnv();
- 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 };
- public float FloatParamMethod(float p){return p;}
- public Vector3 Vector3ParamMethod(Vector3 p){return p;}
- public MyStruct StructParamMethod(MyStruct p){return p;}
- public MyEnum EnumParamMethod(MyEnum p){return p;}
- public decimal DecimalParamMethod(decimal p){return p;}// Use this for initialization
- void Start(){
- luaenv.DoString(@"
- functionid(...)return...endfunctionadd(a, b)return a + b endfunctionarray_exchange(arr)
- arr[0], arr[1]= arr[1], arr[0]endlocal v3 = CS.UnityEngine.Vector3(7,8,9)local vt = CS.XLuaTest.MyStruct(5,6)functionlua_access_csharp()
- monoBehaviour:FloatParamMethod(123)--primitive
- monoBehaviour:Vector3ParamMethod(v3)--vector3local rnd = math.random(1,100)local r = monoBehaviour:Vector3ParamMethod({x =1, y =2, z = rnd})--vector3assert(r.x ==1and r.y ==2and 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]-- fieldend
- exchanger ={
- exchange =function(self, arr)array_exchange(arr)end}
- A ={ B ={ C =789}}
- GDATA =1234;
- ");
- 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);}// Update is called once per frame
- void Update(){// c# call lua function with value type but no gc(using delegate)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>
- 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
- flua();//c# call lua using interface
- ie.exchange(a2);//no gc LuaTable use
- 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);
- 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);
- luaenv.Tick();}
- void OnDestroy(){
- f1 = null;
- f2 = null;
- f3 = null;
- f4 = null;
- f5 = null;
- farr = null;
- flua = null;
- ie = null;
- add = null;
- luaenv.Dispose();}}
复制代码 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|