找回密码
 立即注册
查看: 325|回复: 0

xlua官方Examples例子学习

[复制链接]
发表于 2023-4-11 20:09 | 显示全部楼层 |阅读模式
文章目录

    一 Hello World例子 执行字符串二 执行lua文件,C#与lua交互三 UI绑定与交互四 通过元表,实现lua面向对象五 NoGC Lua访问C#函数无gc


一 Hello World例子 执行字符串
  1. namespaceXLuaTest{publicclassHelloworld:MonoBehaviour{voidStart(){LuaEnv luaenv =newLuaEnv();
  2.             luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");
  3.             luaenv.Dispose();}}}
复制代码
最基本是直接用LuaEnv.DoString执行一个字符串,当然,字符串得符合Lua语法

二 执行lua文件,C#与lua交互

C#文件 LuaBehaviour.cs
  1. 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(){
  2.             scriptEnv = luaEnv.NewTable();// 为每个脚本设置一个独立的环境// 可一定程度上防止脚本间全局变量、函数冲突LuaTable meta = luaEnv.NewTable();
  3.             meta.Set("__index", luaEnv.Global);
  4.             scriptEnv.SetMetaTable(meta);
  5.             meta.Dispose();//设置lua中self为当前C#中的this,方便对当前对象进行操作
  6.             scriptEnv.Set("self",this);//设置lua中通过name来获取GameObjectforeach(var injection in injections){
  7.                 scriptEnv.Set(injection.name, injection.value);}// 加载luaScript变量上挂载的lua,别名为LuaTestScript// 加载到scriptEnv表中
  8.             luaEnv.DoString(luaScript.text,"LuaTestScript", scriptEnv);// C#访问lua中的方法// 注意:通常是用luaenv.Global.Get访问全局方法// 这里是之前设置了元表,meta.Set("__index", luaEnv.Global);Action luaAwake = scriptEnv.Get<Action>("awake");
  9.             scriptEnv.Get("start",out luaStart);
  10.             scriptEnv.Get("update",out luaUpdate);
  11.             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){
  12.                 luaEnv.Tick();
  13.                 LuaBehaviour.lastGCTime = Time.time;}}voidOnDestroy(){if(luaOnDestroy !=null){luaOnDestroy();}
  14.             luaOnDestroy =null;
  15.             luaUpdate =null;
  16.             luaStart =null;
  17.             scriptEnv.Dispose();
  18.             injections =null;}}
复制代码
lua文件 LuaTestScript.lua
  1. local speed =10local lightCpnt =nilfunctionstart()print("lua start...")** 这里lightObject是C#中Injection类通过name来访问GameObject
  2.         ** 简单理解成Unity中组件挂载的GameObject,灯光
  3.         print("injected object", lightObject)
  4.         lightCpnt= lightObject:GetComponent(typeof(CS.UnityEngine.Light))endfunctionupdate()local r = CS.UnityEngine.Vector3.up * CS.UnityEngine.Time.deltaTime * speed
  5.         ** self表示LuaBehaviour.cs中的this,也就是挂载脚本那个对象Cube
  6.         self.transform:Rotate(r)
  7.         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
  1. functionstart()print("lua start...")** 这里的self就是LuaBehaviour组件本身this
  2.         ** 获得Button组件,对onClick注册监听方法
  3.         ** input是注入器绑定的对象,即InputField对象
  4.         ** 这里功能是对按钮注册一个匿名函数,当点击按钮时候,回调匿名函数
  5.         ** 匿名函数是输出输入框中的文本
  6.         self:GetComponent("Button").onClick:AddListener(function()print("clicked, you input is '"..input:GetComponent("InputField").text .."'")end)end
复制代码
Unity中的情况



四 通过元表,实现lua面向对象

C# InvokeLua.cs
  1. 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 =@"
  2.                         *局部 表calc_mt  实际是下面构建一个表A的元表M
  3.                         * 元表M的元方法__index是一个表I
  4.                         * 用于模拟面向对象的
  5.                         * 当我们构建的表A这种寻找一个变量(方法)时候
  6.                         * (1)首先去表找,找的到则返回,若找不到继续下一步
  7.                         * (2)判断表是否有元表,若没有返回nil,若有继续下一步
  8.                         * (3)判断元表中是否有元方法__index,若元方法为nil,则返回nil
  9.                         *      若元方法存在,则判断元方法__index是函数还是一个表
  10.                         *      若元方法是一个函数,则返回函数值
  11.                         *            若元方法是一个表,则将该表作为目标重复(1)(2)(3)
  12.                         * 提示,这里将元表M的元方法__index设为一个表,表里面有许多方法,例如Add
  13.                 local calc_mt = {
  14.                     __index = {
  15.                         Add = function(self, a, b)
  16.                             return (a + b) * self.Mult
  17.                         end,
  18.                         get_Item = function(self, index)
  19.                             return self.list[index + 1]
  20.                         end,
  21.                         set_Item = function(self, index, value)
  22.                             self.list[index + 1] = value
  23.                             self:notify({name = index, value = value})
  24.                         end,
  25.                         add_PropertyChanged = function(self, delegate)
  26.                                 if self.notifylist == nil then
  27.                                         self.notifylist = {}
  28.                                 end
  29.                                 table.insert(self.notifylist, delegate)
  30.                             print('add',delegate)
  31.                         end,                    
  32.                         remove_PropertyChanged = function(self, delegate)
  33.                             for i=1, #self.notifylist do
  34.                                         if CS.System.Object.Equals(self.notifylist[i], delegate) then
  35.                                                 table.remove(self.notifylist, i)
  36.                                                 break
  37.                                         end
  38.                                 end
  39.                             print('remove', delegate)
  40.                         end,
  41.                         notify = function(self, evt)
  42.                                 if self.notifylist ~= nil then
  43.                                         for i=1, #self.notifylist do
  44.                                                 self.notifylist[i](self, evt)
  45.                                         end
  46.                                 end       
  47.                         end,
  48.                     }
  49.                 }
  50.                 * 新建一个表Calc,相关于类,继承与calc_mt
  51.                 * 定义一个全局表,增加一个叫做New的函数
  52.                 * New函数返回一个元表,将calc_mt设置为{}表的元表
  53.                 * {}中函数将mult赋值给Mult,带一个list表
  54.                 Calc = {
  55.                         * New可以理解成构造函数
  56.                         New = function (mult, ...)
  57.                         print(...)
  58.                         return setmetatable({Mult = mult, list = {'aaaa','bbbb','cccc'}}, calc_mt)
  59.                         * 等同于一下写法
  60.                         * local a = {Mult = mult, list = {'aaaa','bbbb','cccc'}}
  61.                         * local b = setmetatable(a, calc_mt)
  62.                         * return b
  63.                     end
  64.                 }
  65.                 ";// Use this for initializationvoidStart(){LuaEnv luaenv =newLuaEnv();Test(luaenv);//调用了带可变参数的delegate,函数结束都不会释放delegate,即使置空并调用GC
  66.             luaenv.Dispose();}voidTest(LuaEnv luaenv){//读取lua代码
  67.             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
  68.             Debug.Log("sum(*10) ="+ calc.Add(1,2));
  69.             calc.Mult =100;//输出 (1+2)*100 = 30
  70.             Debug.Log("sum(*100)="+ calc.Add(1,2));//索引操作会用到get_Item和set_Item//在lua中索引是从1开始//在C#中索引是从0开始,这里是C#
  71.             Debug.Log("list[0]="+ calc[0]);
  72.             Debug.Log("list[1]="+ calc[1]);//委托绑定方法Notify
  73.             calc.PropertyChanged += Notify;
  74.             calc[1]="dddd";
  75.             Debug.Log("list[1]="+ calc[1]);
  76.             calc.PropertyChanged -= Notify;
  77.             calc[1]="eeee";
  78.             Debug.Log("list[1]="+ calc[1]);}voidNotify(object sender,PropertyChangedEventArgs e){
  79.             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#纯值类型
  1. namespace XLuaTest{[GCOptimize][LuaCallCSharp]
  2.     public struct Pedding{
  3.         public byte c;}[GCOptimize][LuaCallCSharp]
  4.     public struct MyStruct{
  5.         public MyStruct(int p1, int p2){
  6.             a = p1;
  7.             b = p2;
  8.             c = p2;
  9.             e.c =(byte)p1;}
  10.         public int a;
  11.         public int b;
  12.         public decimal c;
  13.         public Pedding e;}[LuaCallCSharp]
  14.     public enum MyEnum{
  15.         E1,
  16.         E2
  17.     }[CSharpCallLua]
  18.     public delegate int IntParam(int p);[CSharpCallLua]
  19.     public delegate Vector3 Vector3Param(Vector3 p);[CSharpCallLua]
  20.     public delegate MyStruct CustomValueTypeParam(MyStruct p);[CSharpCallLua]
  21.     public delegate MyEnum EnumParam(MyEnum p);[CSharpCallLua]
  22.     public delegate decimal DecimalParam(decimal p);[CSharpCallLua]
  23.     public delegate void ArrayAccess(Array arr);[CSharpCallLua]
  24.     public interface IExchanger{
  25.         void exchange(Array arr);}[LuaCallCSharp]
  26.     public class NoGc :MonoBehaviour{
  27.         LuaEnv luaenv = new LuaEnv();
  28.         IntParam f1;
  29.         Vector3Param f2;
  30.         CustomValueTypeParam f3;
  31.         EnumParam f4;
  32.         DecimalParam f5;
  33.         ArrayAccess farr;
  34.         Action flua;
  35.         IExchanger ie;
  36.         LuaFunction add;[NonSerialized]
  37.         public double[] a1 = new double[]{1,2};[NonSerialized]
  38.         public Vector3[] a2 = new Vector3[]{ new Vector3(1,2,3), new Vector3(4,5,6)};[NonSerialized]
  39.         public MyStruct[] a3 = new MyStruct[]{ new MyStruct(1,2), new MyStruct(3,4)};[NonSerialized]
  40.         public MyEnum[] a4 = new MyEnum[]{ MyEnum.E1, MyEnum.E2 };[NonSerialized]
  41.         public decimal[] a5 = new decimal[]{1.00001M,2.00002M };
  42.         public float FloatParamMethod(float p){return p;}
  43.         public Vector3 Vector3ParamMethod(Vector3 p){return p;}
  44.         public MyStruct StructParamMethod(MyStruct p){return p;}
  45.         public MyEnum EnumParamMethod(MyEnum p){return p;}
  46.         public decimal DecimalParamMethod(decimal p){return p;}// Use this for initialization
  47.         void Start(){
  48.             luaenv.DoString(@"
  49.                 functionid(...)return...endfunctionadd(a, b)return a + b endfunctionarray_exchange(arr)
  50.                     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()
  51.                     monoBehaviour:FloatParamMethod(123)--primitive
  52.                     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)
  53.                     monoBehaviour:StructParamMethod(vt)--custom struct
  54.                     r = monoBehaviour:StructParamMethod({a =1, b = rnd, e ={c = rnd}})assert(r.b == rnd and r.e.c == rnd)
  55.                     monoBehaviour:EnumParamMethod(CS.XLuaTest.MyEnum.E2)--enum
  56.                     monoBehaviour:DecimalParamMethod(monoBehaviour.a5[0])
  57.                     monoBehaviour.a1[0], monoBehaviour.a1[1]= monoBehaviour.a1[1], monoBehaviour.a1[0]-- fieldend
  58.                 exchanger ={
  59.                     exchange =function(self, arr)array_exchange(arr)end}
  60.                 A ={ B ={ C =789}}
  61.                 GDATA =1234;
  62.             ");
  63.             luaenv.Global.Set("monoBehaviour", this);
  64.             luaenv.Global.Get("id", out f1);
  65.             luaenv.Global.Get("id", out f2);
  66.             luaenv.Global.Get("id", out f3);
  67.             luaenv.Global.Get("id", out f4);
  68.             luaenv.Global.Get("id", out f5);
  69.             luaenv.Global.Get("array_exchange", out farr);
  70.             luaenv.Global.Get("lua_access_csharp", out flua);
  71.             luaenv.Global.Get("exchanger", out ie);
  72.             luaenv.Global.Get("add", out add);
  73.             luaenv.Global.Set("g_int",123);
  74.             luaenv.Global.Set(123,456);
  75.             int i;
  76.             luaenv.Global.Get("g_int", out i);
  77.             Debug.Log("g_int:"+ i);
  78.             luaenv.Global.Get(123, out i);
  79.             Debug.Log("123:"+ i);}// Update is called once per frame
  80.         void Update(){// c# call lua function with value type but no gc(using delegate)f1(1);// primitive type
  81.             f2(new Vector3(1,2,3));// vector3
  82.             MyStruct mystruct1 = new MyStruct(5,6);f3(mystruct1);// custom complex value type
  83.             f4(MyEnum.E1);//enum
  84.             decimal dec1 =-32132143143100109.00010001010M;f5(dec1);//decimal
  85.             // using LuaFunction.Func<T1, T2, TResult>
  86.             add.Func<int, int, int>(34,56);// LuaFunction.Func<T1, T2, TResult>// lua access c# value type array no gc
  87.             farr(a1);//primitive value type array
  88.             farr(a2);//vector3 array
  89.             farr(a3);//custom struct array
  90.             farr(a4);//enum arry
  91.             farr(a5);//decimal arry
  92.             // lua call c# no gc with value type
  93.             flua();//c# call lua using interface
  94.             ie.exchange(a2);//no gc LuaTable use
  95.             luaenv.Global.Set("g_int",456);
  96.             int i;
  97.             luaenv.Global.Get("g_int", out i);
  98.             luaenv.Global.Set(123.0001, mystruct1);
  99.             MyStruct mystruct2;
  100.             luaenv.Global.Get(123.0001, out mystruct2);
  101.             decimal dec2 =0.0000001M;
  102.             luaenv.Global.Set((byte)12, dec1);
  103.             luaenv.Global.Get((byte)12, out dec2);
  104.             int gdata = luaenv.Global.Get<int>("GDATA");
  105.             luaenv.Global.SetInPath("GDATA", gdata +1);
  106.             int abc = luaenv.Global.GetInPath<int>("A.B.C");
  107.             luaenv.Global.SetInPath("A.B.C", abc +1);
  108.             luaenv.Tick();}
  109.         void OnDestroy(){
  110.             f1 =  null;
  111.             f2 = null;
  112.             f3 = null;
  113.             f4 = null;
  114.             f5 = null;
  115.             farr = null;
  116.             flua = null;
  117.             ie = null;
  118.             add = null;
  119.             luaenv.Dispose();}}
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 08:33 , Processed in 0.156156 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表