xLua学习笔记_在C#脚本中使用xLua
https://www.cnblogs.com/guoyujam/p/12238215.html
- 目录 (点击无法跳转的那种 ^_^ )
- 开始
- 加载Lua文件
- 在C#脚本中,获取Lua中的变量
- 在C#脚本中,获取Lua中的表
- 在C#脚本中,获取Lua中的函数
- 官方使用建议
- 自定义Loader加载指定目录的Lua脚本
- 待补充....
- 开始
引入命名空间:
using XLua;
创建Lua的运行环境:
LuaEnv luaenv = new LuaEnv();
这里有一段官方提示:
一个LuaEnv实例对应Lua虚拟机,出于开销的考虑,建议全局唯一。
释放Lua:
luaenv.Dispose();
- 加载Lua文件
注意,当你使用以下方法读取lua文件的时候
luaenv.DoString("require '文件名'");
这个文件名可以不用添加.lua或者.txt的后缀名,但是!这个文件的后缀名真正其实是.txt! 用.lua作为后缀名,Unity不会识别。
哪能不能不用txt作为后缀呢?
这里贴上一段xLua之FAQ中的一部分:
lua源码只能以txt后缀?
什么后缀都可以。
如果你想以TextAsset打包到安装包(比如放到Resources目录),Unity不认lua后缀,这是Unity的规则。
如果你不打包到安装包,就没有后缀的限制:比如自行下载到某个目录(这也是热更的正确姿势),然后通过CustomLoader或者设置package.path去读这个目录。
那为啥xLua本身带的lua源码(包括示例)为什么都是txt结尾呢?因为xLua本身就一个库,不含下载功能,也不方便运行时去某个地方下载代码,通过TextAsset是较简单的方式。
- 在C#脚本中,获取Lua中的变量
首先,官方给的例子是这个样子的:
luaenv.Global.Get<int>("a") luaenv.Global.Get<string>("b") luaenv.Global.Get<bool>("c")
以上代码分别获取了Lua脚本中:
number类型的a string类型的b bool类型的c
这里需要注意的一点是:在获取number类型时,一定要注意接收的类型
当Lua中的number类型是小数时,使用Get<int>来获取会获取不到该值;返回值为0。
但是使用Get<double>(或者float)来获取number类型时,无论是整数还是小数,都可以获取到。
- 在C#脚本中,获取Lua中的表
第一种方法,不推荐,官方描述:
映射到普通class或struct:
要注意的是,这个过程是值拷贝,如果class比较复杂代价会比较大。而且修改class的字段值不会同步到table,反过来也不会。
方法如下:
1 -- 这是lua中的表 2 table = { 3 name = "xm",age = 12 4 }
需要在C#中定义一个与lua表中的元素名称,类型一样,而且必须是public的 (数量可以不一致)的class或者struct;
//这是在C#中定义的类 class MyClass { public string name; public int age; }
准备完毕后调用:
1 MyClass mc = e.Global.Get<MyClass>("table"); 2 print(mc.name); 3 print(mc.age); 4 //输出: 5 //xm 6 //12
使用这种方法时,只能获取到你在C#类中定义的同名变量,若是你在表中定义了第三个变量,不去获取;又或是你在C#类中使用了不一样的名称变量,去获取,都不会得到这个值(不一样名称会为null),同时也不会报错。
第二种方法,官方描述:
映射到一个interface:
这种方式依赖于生成代码(如果没生成代码会抛InvalidCastException异常),代码生成器会生成这个interface的实例,如果get一个属性,生成代码会get对应的table字段,如果set属性也会设置对应的字段。甚至可以通过interface的方法访问lua的函数。
定义一个接口,需与lua表中的元素名称,类型一样 (数量可以不一致)
注意!这个接口必须是public的,且需要在上面加上[CSharpCallLua] ,并且要在Unity中重新生成xLua代码 这里有坑,未来补上
接口:
1 [CSharpCallLua] 2 public interface Itest 3 { 4 string name { get; set; } 5 int age { get; set; } 6 }
调用方法还是和class的差不多:
1 Itest test = luaenv.Global.Get<Itest>("table"); 2 Debug.Log(test.name); 3 Debug.Log(test.age);
第二种方法是引用传递,在C#中修改值,Lua中也会被修改。
- 在C#脚本中,获取Lua中的函数
官方解释:
这种是建议的方式,性能好很多,而且类型安全。缺点是要生成代码(如果没生成代码会抛InvalidCastException异常)。
可以使用委托的方式:
1 [CSharpCallLua] 2 public delegate void testDelegate(int a,int b,int c,int d);
委托同样也需要添加[CSharpCallLua],且需要为public,最后需要在Unity中重新生成xLua才可以使用。这两项缺少一项,都会导致代码报错。
调用方法:
1 testDelegate ad = luaenv.Global.Get<testDelegate>("add"); 2 ad(1, 2, 3, 4);
Lua方面:
1 function add(a,b,c,d) 2 print(a+b+c+d) 3 end
如果有多个返回值,在定义委托的时候,加上out或者ref关键字可达到类似效果:
1 [CSharpCallLua] 2 public delegate void testDelegate(int a,out int o,ref int r);
注意:如果直接 luaenv.Dispose() 的话,会报错:
原因是C#中有变量正在引用着Lua中的东西,需要把C#中的那个变量置空才行。
1 ad = null;
这样操作后,Dispose就不会报错了。
还有一种直接映射到LuaFunction但是性能消耗比上一个要大,用法 及 官方解释:
1 LuaFunction f = luaenv.Global.Get<LuaFunction>("add"); 2 f.Call(1, 2, 3, 4);
这种方式的优缺点刚好和第一种相反。(第一种是 “性能好很多,而且类型安全”)
使用也简单,LuaFunction上有个变参的Call函数,可以传任意类型,任意个数的参数,返回值是object的数组,对应于lua的多返回值。
- 官方使用建议
结合以上的多种实现方法,官方给出的使用建议:
1、访问lua全局数据,特别是table以及function,代价比较大,建议尽量少做,比如在初始化时把要调用的lua function获取一次(映射到delegate)后,保存下来,后续直接调用该delegate即可。table也类似。
2、如果lua测的实现的部分都以delegate和interface的方式提供,使用方可以完全和xLua解耦:由一个专门的模块负责xlua的初始化以及delegate、interface的映射,然后把这些delegate和interface设置到要用到它们的地方。
- 自定义Loader加载指定目录的Lua脚本
设置自定义Loader:
LuaEnv env = new LuaEnv(); env.AddLoader(MyLoader);
AddLoader这个函数的参数是一个 返回值为byte类型数组,参数是ref string类型 的委托,为方便理解,下面贴出详细代码;
红色字体的MyLoader的定义如下:
1 public byte[] MyLoader (ref string filePath) 2 { 3 //方法体 4 return System.Text.Encoding.UTF8.GetBytes("这里是lua文件的路径位置"); 5 }