本来想着一个文章全都写完,后来才发现,失策了!!!,加上自己感觉要是太长了,后面自己复习也懒得去看,那就细分成三个文章咯!毕竟有些地方还是有些区别的
获取全局变量 其实获取全局变量还是比较容易的,首先在项目的Lua文件中创建两个lua脚本
1 2 3 print ("主lua脚本_main.lua_文件启动" )require ("test" )
1 2 3 4 5 6 print ("test.lua脚本调用" )testNumber=1 testBool=true testFloat=1.25 testString="123"
下面就可以直接用c#来获取lua文件夹中的main.lua和test.lua了
1 2 3 4 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("main" );
知识点: 下面获取到全局变量,就用到了lua的相关知识点中的_G表将我们申明的所有全局变量都存储在其中,但是Lua脚本中的本地局部变量的是无法直接获取的
所以我们就可以用_G表来获取全局变量了
1 2 3 4 5 6 7 8 9 10 int i = LuaMgr.GetInstance().Global.Get<int >("testNumber" );Debug.Log("testNumber:" + i); bool b = LuaMgr.GetInstance().Global.Get<bool >("testBool" );Debug.Log("testBool:" + b); float f = LuaMgr.GetInstance().Global.Get<float >("testFloat" );Debug.Log("testFloat:" + f); double d = LuaMgr.GetInstance().Global.Get<double >("testFloat" );Debug.Log("testFloat_double:" + d); string s = LuaMgr.GetInstance().Global.Get<string >("testString" );Debug.Log("testString:" + s);
这样非常明显的看出来,虽然说在lua中的整型,浮点型等都是number,但是可以在c#中转化为相应的类型
对于赋值操作可通过Set(“变量名”,”所要赋的值”)来实现
1 2 3 LuaMgr.GetInstance().Global.Set("testNumber" , 55 ); int i2 = LuaMgr.GetInstance().Global.Get<int >("testNumber" );Debug.Log("testNumber_i2:" + i2);
获取全局函数/方法 其实常见的方法类型无外乎就是以下类型
普通方法(无返回值,无参数,此方法一般应用于相关逻辑的处理)
有参数有返回值
多返回值
方法中不定参数
无参无返回 1 2 3 funcFun=function () print ("无参无返回" ) end
c#中调用lua中的方法一般有几种方式
1 2 3 4 5 6 7 8 9 10 首先需要创建一个委托 public delegate void CallBackOne () ;LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("test" ); CallBackOne callBackOne = LuaMgr.GetInstance().Global.Get<CallBackOne>("funcFun" ); callBackOne();
1 2 3 4 5 6 7 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("test" ); UnityAction unityAction_One = LuaMgr.GetInstance().Global.Get<UnityAction>("funcFun" ); unityAction_One();
1 2 3 4 5 6 7 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("test" ); Action action_One = LuaMgr.GetInstance().Global.Get<Action>("funcFun" ); action_One();
Lua解析器也是提供了获取函数的方式,但是官方也有提到这种方式会造成一些垃圾,因此建议少用
1 2 3 4 5 6 7 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("test" ); LuaFunction luaFunction_One = LuaMgr.GetInstance().Global.Get<LuaFunction>("funcFun" ); luaFunction_One.Call();
有参有返回 1 2 3 4 funcFun2=function (a) print ("有参有返回" ) return a+1 end
这里对于有参数或者有返回的用法是有一些不一样的,因为对于无参无返回是系统内置好的,但是对于有参有返回,多返回以及不定参数,由于系统并未自带,因此需要点击
这时在xLua/Gen文件夹中会生成相应的文件,这里可以简单理解为依赖
但是为了保险起见呢,最好在自定义委托时按照以下写法设置
1 2 [CSharpCallLua ] public delegate int CallBackTwo (int a ) ;
1 2 CallBackTwo callBackTwo = LuaMgr.GetInstance().Global.Get<CallBackTwo>("funcFun2" ); Debug.Log("有参数有返回值:" + callBackTwo(10 ));
1 2 CallBackTwo callBackTwo = LuaMgr.GetInstance().Global.Get<CallBackTwo>("funcFun2" ); Debug.Log("有参数有返回值:" + callBackTwo(10 ));
1 2 Func<int , int > sFun = LuaMgr.GetInstance().Global.Get<Func<int , int >>("funcFun2" ); Debug.Log("c#自带的有参数有返回值:" + sFun(20 ));
1 2 3 LuaFunction luaFunction_Two = LuaMgr.GetInstance().Global.Get<LuaFunction>("funcFun2" ); Debug.Log("xLua提供的有参有会返回值的:" + luaFunction_Two.Call(30 )[0 ]);
多返回值 这里需要用到一个知识点,也就是out和ref的用法
知识点: 在C#中通过使用方法来获取返回值时,通常只能得到一个返回值。因此,当一个方法需要返回多个值 的时候,就需要用到ref和out。
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。(简单来说就是在参数前加ref,并需要先对参数初始化)
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字(简单来说,与ref一样需要在参数前加out,但是比ref不需要先对参数初始化)
1 2 3 4 funcFun3=function (a) print ("多返回值" ) return 1 ,2 ,true ,"哈信息" ,a end
定义与lua中相同的委托
1 2 3 [CSharpCallLua ] public delegate int CallBackFour (int a, ref int b, ref bool c, ref string d, ref int e ) ;
需要先对相关参数变量进行初始化
1 2 3 4 5 6 7 int b1 = 0 ;bool c1 = true ;string d1 = "" ;int e1 = 0 ;CallBackFour call4 = LuaMgr.GetInstance().Global.Get<CallBackFour>("funcFun3" ); Debug.Log("使用ref" + call4(200 , ref b1, ref c1, ref d1, ref e1)); Debug.Log(b1 + "_" + c1 + "_" + d1 + "_" + e1);
定义与lua中相同的委托
1 2 [CSharpCallLua] public delegate int CallBackThree(int a, out int b, out bool c, out string d, out int e)
创建相关参数变量
1 2 3 4 5 6 7 CallBackThree call3 = LuaMgr.GetInstance().Global.Get<CallBackThree>("funcFun3" ); int b;bool c;string d;int e;Debug.Log("第一个返回值:" + call3(100 , out b, out c, out d, out e)); Debug.Log(b + "_" + c + "_" + d + "_" + e);
不定参数 1 2 3 4 5 6 7 8 funcFun4=function (a,...) print ("变长参数" ) print (a) arg ={...} for k,v in pairs (arg ) do print (k,v) end end
C#映射到Lua 列表和字典映射 列表映射Lua 简述:List可以包含指定类型的元素。它提供编译时类型检查,并且不执行装箱/拆箱,因为它是泛型的。
首先还是需要在lua中实现一个列表的效果,这个还是比较简单,因为列表是可以存相同类型的数据,也可存储不同类型的数据,而lua中是以table来实现相应的效果,这里为了模拟实际中常见的使用创建两个table
1 2 3 testList={1 ,2 ,3 ,4 ,5 ,6 } testListTwo={"123" ,"456" ,true ,1 ,1 ,2 }
在c#中使用首先还是需要初始化lua解析器
1 2 3 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("main" );
然后我们就可以用大G表去获取到两个lua中的table表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 List<int > listOne = LuaMgr.GetInstance().Global.Get<List<int >>("testList" ); foreach (var item in listOne){ Debug.Log(item); } List<object > listTwo = LuaMgr.GetInstance().Global.Get<List<object >>("testListTwo" ); foreach (var item in listTwo){ Debug.Log(item); }
字典映射Lua 其实对于字典来说,在lua中基本就是table1套table2,table2中有两个变量,一个用来存键,一个用来值
1 2 3 4 5 6 7 8 9 10 11 12 13 testDic={ ["1" ]=1 , ["2" ]=2 , ["3" ]=3 , ["4" ]=4 } testDicTwo={ ["1" ]=1 , [true ]=1 , [false ]=true , ["456" ]=false }
在c#中使用首先还是需要初始化lua解析器
1 2 3 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("main" );
然后创建字典用大G表获取到testDic和testDicTwo
1 2 3 4 5 6 7 8 Dictionary<string , int > dic = LuaMgr.GetInstance().Global.Get<Dictionary<string , int >>("testDic" ); foreach (string item in dic.Keys) { Debug.Log(item + "_" + dic[item]); } Dictionary<object , object > dicTwo = LuaMgr.GetInstance().Global.Get<Dictionary<object , object >>("testDicTwo" ); foreach (object item in dicTwo.Keys) { Debug.Log(item + "_" + dicTwo[item]); }
类映射Lua的table 基本使用 在lua中创建类基本和c#中创建一个类相比较有些类似,只是在表中加入参数和函数
1 2 3 4 5 6 7 8 9 testClass={ testInt=2 , testBool=true , testFloat=1.2 , testString="123" , testFun=function () print ("123456789" ) end }
对于在C#中如何使用,基本就是在创建相同名称的公有变量(这里需要注意私有和保护的变量是无法获取到的,而且公有变量是可多可少的,如果某个变量不需要,可以不写,结果只会被忽略得不到值而已,多出的变量也不会赋值,并且自动忽略,不会影响整体的效果,而类属于值传递,并不会造成lua变量的值的变化 )
1 2 3 4 5 6 7 8 9 10 --我们先创建和lua中相同名字的类 public class CallLuaClass { public int testInt; public bool testBool; public float testFloat; public float testString; public UnityAction testFun; }
1 2 3 4 5 6 7 8 9 10 11 12 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("Main" ); CallLuaClass obj = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass" ); Debug.Log(obj.testInt); Debug.Log(obj.testBool); Debug.Log(obj.testFloat); Debug.Log(obj.testString); obj.testFun();
这里我们可以通过以下的截图看出结果
当我们注释掉testFloat这个变量,如下
1 2 3 4 5 6 7 8 9 10 11 --我们先创建和lua中相同名字的类 public class CallLuaClass { public int testInt; public bool testBool; public float testFloatTwo; public float testString; public UnityAction testFun; }
按照上面的方式进行打印
1 2 3 4 5 6 7 8 9 10 11 12 13 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("Main" ); CallLuaClass obj = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass" ); Debug.Log(obj.testInt); Debug.Log(obj.testBool); Debug.Log(obj.testFloatTwo); Debug.Log(obj.testString); obj.testFun();
这里很容易会发现,结果不会受影响,并且没有找到的testFloatTwo这个变量结果也并没有进行赋值,而是默认值为0
进阶 其实在实际的开发过程中,不可能单单是一类,也存在类中在套着类的情况,这种情况对于lua中的写法来说,无外乎就是table套table,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 testClass={ testInt=2 , testBool=true , testFloat=1.2 , testString="123" , testFun=function () print ("123456789" ) end , testInClass= { testInInt=5 } }
在C#来说就是在创建一个Class类,然后在类中添加,例如(需要注意:lua中的表名要和c#中类名要保持一致 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class CallLuaClass { public int testInt; public bool testBool; //public float testFloat; public float testString; public UnityAction testFun; public CallLuaInClass testInClass; public void Test() { Debug.Log(testInt); } } public class CallLuaInClass { public int testInInt; }
具体的调用
1 2 3 4 5 6 7 8 9 10 11 12 13 //初始化Lua解析器 LuaMgr.GetInstance().Init(); //加载lua脚本 LuaMgr.GetInstance().DoLuaFile("Main" ); //获取到testClass这个表并与CallLuaClass意义对应 CallLuaClass obj = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass" ); Debug.Log(obj.testInt); Debug.Log(obj.testBool); //Debug.Log(obj.testFloat); Debug.Log(obj.testString); Debug.Log(obj.i); Debug.Log("嵌套:" + obj.testInClass.testInInt); obj.testFun();
接口映射Lua的table 其实接口和类规则一样,也遵循公有变量是可多可少的,如果某个变量不需要,可以不写,结果只会被忽略得不到值而已,多出的变量也不会赋值,并且自动忽略,不会影响整体的效果,但是由于接口拷贝是引用拷贝,对于数值的赋值会影响到lua中的参数数值
,例如
### 首先创建一个接口
接口中是不允许有成员变量的,我们用属性来接受,而且用接口来接收lua参数是需要添加[CSharpCallLua]
1 2 3 4 5 6 7 8 9 [CSharpCallLua ] public interface ICSharpCallInterface { int testInt{ get ;set ; } bool testBool{ get ;set ; } string testString { get ;set ; } UnityAction testFun { get ;set ; } }
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 LuaMgr.GetInstance().Init(); LuaMgr.GetInstance().DoLuaFile("Main" ); ICSharpCallInterface obj = LuaMgr.GetInstance().Global.Get<ICSharpCallInterface>("testClass" ); Debug.Log(obj.testInt); Debug.Log(obj.testBool); Debug.Log(obj.testString); obj.testFun(); obj.testInt = 10000 ; ICSharpCallInterface obj2 = LuaMgr.GetInstance().Global.Get<ICSharpCallInterface>("testClass" ); Debug.Log(obj2.testInt);
LuaTable映射table 其实这种方式,在官方的文档中是不建议使用的,因为其会造成多余的垃圾,如果不进行清理,会造成垃圾的存留,或多或少的造成效率的降低
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 LuaMgr.GetInstance().DoLuaFile("Main" ); LuaTable table = LuaMgr.GetInstance().Global.Get<LuaTable>("testClas" ); Debug.Log(table.Get<int >("testInt" )); Debug.Log(table.Get<bool >("testBool" )); Debug.Log(table.Get<float >("testFloat" )); Debug.Log(table.Get<string >("testString" )); table.Get<LuaFunction>("testFun" ).Call(); table.Set("testInt" , 55 ); Debug.Log(table.Get<int >("testInt" )); LuaTable table2 = LuaMgr.GetInstance().Global.Get<LuaTable>("testClas" ); Debug.Log(table2.Get<int >("testInt" )); table.Dispose(); table2.Dispose();