文章目录

  • 热更新介绍
  • Xlua
  • 开发工具推荐
  • C#调用lua
  • lua文件加载
  • Loader自定义加载
  • lua调用C#的例子

热更新介绍

目前来说主流的热更新方案还是lua,其中ulua,ToLua,Xlua,这三个是比较热门的。

Tolua继承自ulua

http://www.ulua.org/index.html 点开

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别

Xlua

https://github.com/Tencent/xLua xlua学习,首先看一遍文档中必看的教程和配置文件

Xlua tolua区别 ulua和xlua比较_加载_02

C#访问Lua

Xlua tolua区别 ulua和xlua比较_后缀_03

Lua访问C#

Xlua tolua区别 ulua和xlua比较_lua_04


Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_05


注意:xlua只一定程度上支持重载函数的调用,因为lua的类型远远不如C#丰富,存在一对多的情况,比如C#的int,float,double都对应于lua的number,上面的例子中TestFunc如果有这些重载参数,第一行将无法区分开来,只能调用到其中一个(生成代码中排前面的那个)

Xlua tolua区别 ulua和xlua比较_后缀_06

看完xlua给的配置和教程,我们逐个跑一下给的例子,结合教程和配置文件体会一下xlua在开发中的使用

安装xlua到一个空项目

Xlua tolua区别 ulua和xlua比较_加载_07

开发工具推荐

我这里使用vscode开发lua,有条件可以用rider

Xlua tolua区别 ulua和xlua比较_后缀_08


打开以后lua文件的后缀带有.txt,vscode无法识别,为什么是txt后缀呢?可不可以改呢?来看官方回答

Xlua tolua区别 ulua和xlua比较_lua_09


总结:lua后缀可以用非txt后缀,且也是官方所推荐的,我也认为热更应该是需要的地方再用,且保守使用,而不是随便植入。

所以我们把txt后缀删了看看

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_10


这下vscode可以识别了。(识别后加回txt后缀依然可以识别

我们再用rider打开看看

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_11


Xlua tolua区别 ulua和xlua比较_lua_12


我下载的是Emmylua插件,可以看到也是只识别lua后缀,对于txt后缀是不识别的

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_13

后续我建议有条件就rider开发,C#和lua混合开发体验会好很多,vscode开发C#还是有差距,当然可以vscode+vs这样。后面就用vscode来开发(rider30天体验已到期)

打开之后,我们可以看到Xlua教程有三个

Xlua tolua区别 ulua和xlua比较_加载_14

第一个例子是

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中加入了函数)我们来自己写一个试试看

Xlua tolua区别 ulua和xlua比较_lua_15

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_16

第二个教程

lua文件加载

加载lua文件 用lua的require函数即可 比如:DoString(“require ‘byfile’”)

这里可以看xlua的教程中加载的部分

Xlua tolua区别 ulua和xlua比较_加载_17

需要注意的是,lua文件要放在Resources文件下,后缀要为txt(不然Resources不识别),方可成功加载。按照教程,我们添加一个main

Xlua tolua区别 ulua和xlua比较_lua_18


Xlua tolua区别 ulua和xlua比较_加载_19


然后我们在main 里面再加载需要的文件

Xlua tolua区别 ulua和xlua比较_加载_20

Xlua tolua区别 ulua和xlua比较_lua_21

Xlua tolua区别 ulua和xlua比较_加载_22

既然是根据Resources加载,那么如果有多个呢

在Assets下的Resources放一个,在C#脚本所在位置放一个,会发现会调用C#脚本下的Resources文件中对应的脚本,如果不存在,再找其他位置的lua脚本

Xlua tolua区别 ulua和xlua比较_加载_23

Xlua tolua区别 ulua和xlua比较_后缀_24

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_25

可以看到成功加载。

除此之外,也可以直接在dostring写

Xlua tolua区别 ulua和xlua比较_后缀_26

Xlua tolua区别 ulua和xlua比较_加载_27

Loader自定义加载

教程中说明require 是根据loader加载的,来试试自定义loader(比如我们不希望从Resources加载,希望从我们自定义的文件加载)

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_28


教程中使用了Lambda表达式来写(匿名函数,不用声明函数名),我们可以仿照这些,也可以不用lambda

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_29


可以看到这个接口是返回一个byte数组,所以我们只要写一个返回byte数组的函数,即可用AddLoader添加,里面的传进一个filepath,这是文件名(加载的lua文件名),

我们只要在loader里面处理,得到lua脚本的全部内容且转换为数组返回即可(如果lua脚本在网上,可以从网上下载,或者lua脚本在我们指定的文件夹)

访问指定文件夹需要知道不同平台文件夹路径:

Xlua tolua区别 ulua和xlua比较_lua_30

挑一个application datapath实验

Xlua tolua区别 ulua和xlua比较_加载_31


Xlua tolua区别 ulua和xlua比较_lua_32


Xlua tolua区别 ulua和xlua比较_加载_33


最后一个是

lua调用C#的例子

我们把lua部分复制出来,这样看起来更清楚,作者给的注释很详细,需要用的地方照着写就行,作者在xlua教程里面对于lua调用C#也有很详细的介绍。

Xlua tolua区别 ulua和xlua比较_lua_34


总结:

new对象要用CS.命名空间.对象()

静态属性的读取用CS,写入也用CS,静态方法的调用直接写方法名(所有需要再lua调用的C#方法,属性都要加【LuaCallCSharp】)

将C#要调用的类保存在lua本地,这样就不用每次通过CS频繁调用

Xlua tolua区别 ulua和xlua比较_加载_35

C#的枚举类型lua也可以直接用CS访问

Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_36


Xlua tolua区别 ulua和xlua比较_Xlua tolua区别_37


这三个例子分别展示了lua与C#之间相互调用的全部过程,为热更新打下基础,下一篇我们来看看xlua的热更新步骤,xlua官方对于热更新是如何做的。