文章目录
- 热更新介绍
- Xlua
- 开发工具推荐
- C#调用lua
- lua文件加载
- Loader自定义加载
- lua调用C#的例子
热更新介绍
目前来说主流的热更新方案还是lua,其中ulua,ToLua,Xlua,这三个是比较热门的。
Tolua继承自ulua
http://www.ulua.org/index.html 点开
Xlua
https://github.com/Tencent/xLua xlua学习,首先看一遍文档中必看的教程和配置文件
C#访问Lua
Lua访问C#
注意:xlua只一定程度上支持重载函数的调用,因为lua的类型远远不如C#丰富,存在一对多的情况,比如C#的int,float,double都对应于lua的number,上面的例子中TestFunc如果有这些重载参数,第一行将无法区分开来,只能调用到其中一个(生成代码中排前面的那个)
看完xlua给的配置和教程,我们逐个跑一下给的例子,结合教程和配置文件体会一下xlua在开发中的使用
安装xlua到一个空项目
开发工具推荐
我这里使用vscode开发lua,有条件可以用rider
打开以后lua文件的后缀带有.txt,vscode无法识别,为什么是txt后缀呢?可不可以改呢?来看官方回答
总结:lua后缀可以用非txt后缀,且也是官方所推荐的,我也认为热更应该是需要的地方再用,且保守使用,而不是随便植入。
所以我们把txt后缀删了看看
这下vscode可以识别了。(识别后加回txt后缀依然可以识别)
我们再用rider打开看看
我下载的是Emmylua插件,可以看到也是只识别lua后缀,对于txt后缀是不识别的
后续我建议有条件就rider开发,C#和lua混合开发体验会好很多,vscode开发C#还是有差距,当然可以vscode+vs这样。后面就用vscode来开发(rider30天体验已到期)
打开之后,我们可以看到Xlua教程有三个
第一个例子是
C#调用lua
里面都有详细的注释,这里总结一下流程。首先建立一个全局的luaenv,然后加载lua脚本(用DoString 方法),lua的全局变量用Get直接访问,访问全局表用interface映射,全局函数用delgate映射(也是作者建议使用的方法)
void Start()
{
luaenv = new LuaEnv();
luaenv.DoString(script);
Debug.Log("_G.a = " + luaenv.Global.Get<int>("a"));
Debug.Log("_G.b = " + luaenv.Global.Get<string>("b"));
Debug.Log("_G.c = " + luaenv.Global.Get<bool>("c"));
DClass d = luaenv.Global.Get<DClass>("d");//映射到有对应字段的class,by value
Debug.Log("_G.d = {f1=" + d.f1 + ", f2=" + d.f2 + "}");
Dictionary<string, double> d1 = luaenv.Global.Get<Dictionary<string, double>>("d");//映射到Dictionary<string, double>,by value
Debug.Log("_G.d = {f1=" + d1["f1"] + ", f2=" + d1["f2"] + "}, d.Count=" + d1.Count);
List<double> d2 = luaenv.Global.Get<List<double>>("d"); //映射到List<double>,by value
Debug.Log("_G.d.len = " + d2.Count);
ItfD d3 = luaenv.Global.Get<ItfD>("d"); //todo 映射到interface实例,by ref,这个要求interface加到生成列表,否则会返回null,建议用法
d3.f2 = 1000;
Debug.Log("_G.d = {f1=" + d3.f1 + ", f2=" + d3.f2 + "}");
Debug.Log("_G.d:add(1, 2)=" + d3.add(1, 2));
LuaTable d4 = luaenv.Global.Get<LuaTable>("d");//映射到LuaTable,by ref
Debug.Log("_G.d = {f1=" + d4.Get<int>("f1") + ", f2=" + d4.Get<int>("f2") + "}");
Action e = luaenv.Global.Get<Action>("e");//todo 映射到一个delgate,要求delegate加到生成列表,否则返回null,建议用法
e();
FDelegate f = luaenv.Global.Get<FDelegate>("f");
DClass d_ret;
int f_ret = f(100, "John", out d_ret);//lua的多返回值映射:从左往右映射到c#的输出参数,输出参数包括返回值,out参数,ref参数
Debug.Log("ret.d = {f1=" + d_ret.f1 + ", f2=" + d_ret.f2 + "}, ret=" + f_ret);
GetE ret_e = luaenv.Global.Get<GetE>("ret_e");//delegate可以返回更复杂的类型,甚至是另外一个delegate
e = ret_e();
e();
LuaFunction d_e = luaenv.Global.Get<LuaFunction>("e");
d_e.Call();
}
interface也可以访问函数(在table中加入了函数)我们来自己写一个试试看
第二个教程
lua文件加载
加载lua文件 用lua的require函数即可 比如:DoString(“require ‘byfile’”)
这里可以看xlua的教程中加载的部分
需要注意的是,lua文件要放在Resources文件下,后缀要为txt(不然Resources不识别),方可成功加载。按照教程,我们添加一个main
然后我们在main 里面再加载需要的文件
既然是根据Resources加载,那么如果有多个呢
在Assets下的Resources放一个,在C#脚本所在位置放一个,会发现会调用C#脚本下的Resources文件中对应的脚本,如果不存在,再找其他位置的lua脚本
可以看到成功加载。
除此之外,也可以直接在dostring写
Loader自定义加载
教程中说明require 是根据loader加载的,来试试自定义loader(比如我们不希望从Resources加载,希望从我们自定义的文件加载)
教程中使用了Lambda表达式来写(匿名函数,不用声明函数名),我们可以仿照这些,也可以不用lambda
可以看到这个接口是返回一个byte数组,所以我们只要写一个返回byte数组的函数,即可用AddLoader添加,里面的传进一个filepath,这是文件名(加载的lua文件名),
我们只要在loader里面处理,得到lua脚本的全部内容且转换为数组返回即可(如果lua脚本在网上,可以从网上下载,或者lua脚本在我们指定的文件夹)
访问指定文件夹需要知道不同平台文件夹路径:
挑一个application datapath实验
最后一个是
lua调用C#的例子
我们把lua部分复制出来,这样看起来更清楚,作者给的注释很详细,需要用的地方照着写就行,作者在xlua教程里面对于lua调用C#也有很详细的介绍。
总结:
new对象要用CS.命名空间.对象()
静态属性的读取用CS,写入也用CS,静态方法的调用直接写方法名(所有需要再lua调用的C#方法,属性都要加【LuaCallCSharp】)
将C#要调用的类保存在lua本地,这样就不用每次通过CS频繁调用
C#的枚举类型lua也可以直接用CS访问
这三个例子分别展示了lua与C#之间相互调用的全部过程,为热更新打下基础,下一篇我们来看看xlua的热更新步骤,xlua官方对于热更新是如何做的。