NoiseFloor 发表于 2021-8-13 10:00

xLua学习案例

xLua使用案例

需引用命名空间XLua

简单案例1 在c#中直接调用lua代码
LuaEnv luaEnv =null;privatevoidStart(){//创建lua的运行环境 为防止内存大量消耗 建议全局里只存在一个实例
      luaEnv =newLuaEnv();//需要传递一个字符串 内容为lua程序
      luaEnv.DoString("print('helloxLua')");//通过c#调用lua
      luaEnv.DoString(" CS.UnityEngine.Debug.Log('helloxLua') ");//通过lua调用C#//luaEnv.Dispose();}privatevoidOnDestroy(){//在代码执行完后释放luaEnv
      luaEnv.Dispose();}
**简单案例2 ** 通过加载运行lua源文件
通过Resources加载
注:为能使Resources方法能够读取到lua文件 lua文件后缀需为.lua.txt
privateLuaEnv luaenv;privatevoidStart(){
      luaenv =newLuaEnv();TextAsset ta = Resources.Load<TextAsset>("helloWorld.lua");
      luaenv.DoString(ta.text);
      luaenv.Dispose();}通过loader加载(lua文件需放在Resources文件夹 后缀为.lua.txt)
注(引用自xLua作者原话):
require实际上是调一个个的loader去加载,有一个成功就不再往下尝试,全失败则报文件找不到。
目前xLua除了原生的loader外,还添加了从Resource加载的loader,需要注意的是因为Resource只支持有限的后缀,放Resources下的lua文件得加上txt后缀(见附带的例子)。
建议的加载Lua脚本方式是:整个程序就一个DoString(“require ‘main’”),然后在main.lua加载其它脚本(类似lua脚本的命令行执行:lua main.lua)。
privateLuaEnv luaenv;privatevoidStart(){
      luaenv =newLuaEnv();
      luaenv.DoString("require 'helloWorld'");
      luaenv.Dispose();}
简单案例3 Loader方法
添加自定义的Loader方法
privatevoidStart(){LuaEnv luaenv =newLuaEnv();
      luaenv.AddLoader(Add);//添加自定义Loader方法 传递参数是一个委托
      luaenv.DoString(" require 'helloWorld'");
      luaenv.Dispose();}//如果自定义的loader没有返回字节数组 会继续寻找系统内置的loaderprivatebyte[]Add(refstring filePath)//传参为lua文件路径 {string s ="print('Add')";//s为lua脚本内容return System.Text.Encoding.UTF8.GetBytes(s);//将Text文本转成字节数组}通过自定义路径加载指定目录的lua文件
privatevoidStart(){LuaEnv luaenv =newLuaEnv();
      luaenv.AddLoader(Add);//添加自定义Loader方法 传递参数是一个委托
      luaenv.DoString(" require 'add'");
      luaenv.Dispose();}//如果自定义的loader没有返回字节数组 会继续寻找系统内置的loaderprivatebyte[]Add(refstring filePath)//传参为lua文件路径 {string path = Application.streamingAssetsPath +"/"+ filePath +".lua.txt";//得到lua文件路径string s= File.ReadAllText(path);//读取txt文件return System.Text.Encoding.UTF8.GetBytes(s);//将Text文本转成字节数组}

[*]简单案例4 通过c#访问lua中的数据
首先是以下案例中lua的代码
a=233;
str="SKr"
now=true;
person={
        name="小明",
        age=10,
think=function()
        print("我从哪来?")
end,
        --有参数的方法的第一个参数务必加上self(变量名可以是合法的任意值,但一定要加上这个参数)
--self参数代表当前表,在未设置该参数的情况下会作为隐藏参数存在
        add=function(arg,a,b)
        print(a+b)
        end,
        2,4,6,8,10
}
function person:add2(a,b) --通过:调用可以不用传递参数(),系统会自动传递当前的表
    print(a+b)
end
function person.add3(self,a,b) --通过.调用必须传递自身,self不会自动赋值,我们必须通过第一个参数
    print(a+b)
end
通过c#访问lua中的全局变量
privatevoidStart(){LuaEnv luaenv =newLuaEnv();
      luaenv.DoString("require 'CSharpCallLua'");//获取lua中的全局变量int a = luaenv.Global.Get<int>("a");//num对应int float double三个类型
          Debug.Log(a);string str = luaenv.Global.Get<string>("SKr");
          Debug.Log(str);bool now = luaenv.Global.Get<bool>("now");
          Debug.Log(now);
      luaenv.Dispose();}1.通过c#访问lua中的表(映射到普通class或struct)
? 注:这种方式下xLua会帮你new一个实例,并把对应的字段赋值过去。这个过程是值拷贝,如果class比较复杂代价会比较大。而且修改class的字段值不会同步到table,反过来也不会。

classPerson{publicstring name;publicint age;}Start函数
Person person = luaenv.Global.Get<Person>("person");
Debug.Log(person);
Debug.Log(person.name);
Debug.Log(person.age);
luaenv.Dispose();2.通过c#访问lua中的表(映射到接口)
注!:如果改了接口后,之前生成的代码出现错误,执行“Clear Generated Code”菜单!!!

接口
//lua映射到接口一定要加上这个特性interfaceIPerson{string name {get;set;}int age {get;set;}voidthink();}Start函数
IPerson p = luaenv.Global.Get<IPerson>("person");
Debug.Log(p.name);
p.name ="小李";// 通过c#更改lua中的变量
Debug.Log(p.name);
p.think();//执行lua中的方法
luaenv.Dispose();lua方法也可以通过以下方式来定义
person={
      name="小明",
        age=10
}
function person:add2(a,b) --通过:调用可以不用传递参数(),系统会自动传递当前的表
      print(a+b)
end
function person.add3(self,a,b) --通过.调用必须传递自身,self不会自动赋值,我们必须通过第一个参数来传递当前的table
      print(a+b)
end3.通过c#访问lua中的表(映射到Dictionary或者List)
Start函数
...
Dictionary<string,object> dic = luaenv.Global.Get<Dictionary<string,object>("person");foreach(var item in dic){print(item);//通过dic映射过来的值只会映射有对应键的值}

List<object> list = luaenv.Global.Get<List<object>>("person");foreach(var item in list){print(item);/通过list映射过来的值只会映射没有对应键的值
}
luaenv.Dispose();...4.通过c#访问lua中的表(映射到LuaTable类)
注:这种方式好处是不需要生成代码,但也有一些问题,比如慢,比方式2要慢一个数量级,比如没有类型检查。一般情况下推荐使用第二种方式,少用第四种方式
Start函数
...LuaTable tab = luaenv.Global.Get<LuaTable>("person");print(tab.Get<string>("name"));print(tab.Get<int>("age"));
luaenv.Dispose();...通过c#访问lua中的全局函数(映射到delegate)
lua
function fun1()
        print("fun1!")
end

function fun2(a,b)
        print(a+b)
end

function fun3(a,b)
        return a+b
endc#
publicclassCSharpCallLuaTest:MonoBehaviour{LuaEnv luaenv =null;privatevoidStart(){
          luaenv =newLuaEnv();
          luaenv.DoString("require 'CSharpCallLua'");//无参数委托Action fun1 = luaenv.Global.Get<Action>("fun1");fun1();
          fun1 =null;//删除c#对lua函数的引用使得lua虚拟机能顺利释放内存//传参委托Fun2 fun2 = luaenv.Global.Get<Fun2>("fun2");fun2(2,4);
          fun2 =null;//传参委托带返回值Fun3 fun3 = luaenv.Global.Get<Fun3>("fun3");int res=fun3(2,4);print(res);
          fun3 =null;//传参委托带多个返回值int resC;int resD;Fun4 fun4 = luaenv.Global.Get<Fun4>("fun4");//使用out来接受第一个返回值以外的返回值 ref同理但要注意赋初值int resAB =fun4(2,4,out resC,out resD);print(resAB);print(resC);print(resD);
          fun4 =null;

          luaenv.Dispose();}//委托必须加上CSharpCallLua特性delegatevoidFun2(int a,int b);delegateintFun3(int a,int b);delegateintFun4(int a,int b,outint c,outint d);通过c#访问lua中的全局函数(映射到LuaFunction)
lua代码见上文
c#
//通过LuaFunction映射lua方法比较耗费性能 一般不推荐使用LuaFunction luaFun = luaenv.Global.Get<LuaFunction>("fun4");object[] calls= luaFun.Call(2,5);foreach(var item in calls){print(item);}
luaenv.Dispose();xLua作者的使用建议:
1、访问lua全局数据,特别是table以及function,代价比较大,建议尽量少做,比如在初始化时把要调用的lua function获取一次(映射到delegate)后,保存下来,后续直接调用该delegate即可。table也类似。
2、如果lua测的实现的部分都以delegate和interface的方式提供,使用方可以完全和xLua解耦:由一个专门的模块负责xlua的初始化以及delegate、interface的映射,然后把这些delegate和interface设置到要用到它们的地方。
简单案例5 通过lua访问c#中的数据
lua
--需要经常访问的类,可以先用局部变量引用后访问
--所有C#相关的都放到CS下即以CS开头
local gameObject=CS.UnityEngine.GameObject
--lua里头没有new关键字 可以拥有这种方式创建一个GameObject对象
gameObject("new")
--通过lua代码改变Unity中的相机名字
local camera=gameObject.Find("Main Camera")
--修改camera对象的名字
camera.name="ChangeName"
--得到camera对象的Camera组件 使用:会把当前的对象当作第一个参数传递过去
--建议所有的成员方法都通过:来调用
--local cameraCom=camera.GetComponent(camera,"Camera")//用.调用需要传递当前对象
local cameraCom=camera:GetComponent("Camera")
--摧毁相机组件
gameObject.Destroy(cameraCom)c#
privatevoidStart(){LuaEnv luaenv =newLuaEnv();
      luaenv.DoString("require 'LuaCallCSharp'");

      luaenv.Dispose();}
页: [1]
查看完整版本: xLua学习案例