找回密码
 立即注册
查看: 294|回复: 0

xLua学习案例

[复制链接]
发表于 2021-8-13 10:00 | 显示全部楼层 |阅读模式
xLua使用案例

需引用命名空间XLua

    简单案例1 在c#中直接调用lua代码
  1. LuaEnv luaEnv =null;privatevoidStart(){//创建lua的运行环境 为防止内存大量消耗 建议全局里只存在一个实例
  2.         luaEnv =newLuaEnv();//需要传递一个字符串 内容为lua程序
  3.         luaEnv.DoString("print('helloxLua')");//通过c#调用lua
  4.         luaEnv.DoString(" CS.UnityEngine.Debug.Log('helloxLua') ");//通过lua调用C#//luaEnv.Dispose();}privatevoidOnDestroy(){//在代码执行完后释放luaEnv
  5.         luaEnv.Dispose();}
复制代码
    **简单案例2 ** 通过加载运行lua源文件
    通过Resources加载
    注:为能使Resources方法能够读取到lua文件 lua文件后缀需为.lua.txt
  1. privateLuaEnv luaenv;privatevoidStart(){
  2.         luaenv =newLuaEnv();TextAsset ta = Resources.Load<TextAsset>("helloWorld.lua");
  3.         luaenv.DoString(ta.text);
  4.         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)。
  1. privateLuaEnv luaenv;privatevoidStart(){
  2.         luaenv =newLuaEnv();
  3.         luaenv.DoString("require 'helloWorld'");
  4.         luaenv.Dispose();}
复制代码
    简单案例3 Loader方法
    添加自定义的Loader方法
  1. privatevoidStart(){LuaEnv luaenv =newLuaEnv();
  2.         luaenv.AddLoader(Add);//添加自定义Loader方法 传递参数是一个委托
  3.         luaenv.DoString(" require 'helloWorld'");
  4.         luaenv.Dispose();}//如果自定义的loader没有返回字节数组 会继续寻找系统内置的loaderprivatebyte[]Add(refstring filePath)//传参为lua文件路径 {string s ="print('Add')";//s为lua脚本内容return System.Text.Encoding.UTF8.GetBytes(s);//将Text文本转成字节数组}
复制代码
    通过自定义路径加载指定目录的lua文件
  1. privatevoidStart(){LuaEnv luaenv =newLuaEnv();
  2.         luaenv.AddLoader(Add);//添加自定义Loader方法 传递参数是一个委托
  3.         luaenv.DoString(" require 'add'");
  4.         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的代码
    1. a=233;
    2. str="SKr"
    3. now=true;
    4. person={
    5.         name="小明",
    6.         age=10,
    7. think=function()
    8.         print("我从哪来?")
    9. end,
    10.         --有参数的方法的第一个参数务必加上self(变量名可以是合法的任意值,但一定要加上这个参数)
    11. --self参数代表当前表,在未设置该参数的情况下会作为隐藏参数存在
    12.         add=function(arg,a,b)
    13.         print(a+b)
    14.         end,
    15.         2,4,6,8,10
    16. }
    17. function person:add2(a,b) --通过:调用可以不用传递参数(),系统会自动传递当前的表
    18.     print(a+b)
    19. end
    20. function person.add3(self,a,b) --通过.调用必须传递自身,self不会自动赋值,我们必须通过第一个参数
    21.     print(a+b)
    22. end
    复制代码
通过c#访问lua中的全局变量
  1. privatevoidStart(){LuaEnv luaenv =newLuaEnv();
  2.         luaenv.DoString("require 'CSharpCallLua'");//获取lua中的全局变量int a = luaenv.Global.Get<int>("a");//num对应int float double三个类型
  3.           Debug.Log(a);string str = luaenv.Global.Get<string>("SKr");
  4.           Debug.Log(str);bool now = luaenv.Global.Get<bool>("now");
  5.           Debug.Log(now);
  6.         luaenv.Dispose();}
复制代码

1.通过c#访问lua中的表(映射到普通class或struct)
? 注:这种方式下xLua会帮你new一个实例,并把对应的字段赋值过去。这个过程是值拷贝,如果class比较复杂代价会比较大。而且修改class的字段值不会同步到table,反过来也不会。
  1. classPerson{publicstring name;publicint age;}
复制代码
Start函数
  1. Person person = luaenv.Global.Get<Person>("person");
  2.   Debug.Log(person);
  3.   Debug.Log(person.name);
  4.   Debug.Log(person.age);
  5. luaenv.Dispose();
复制代码
2.通过c#访问lua中的表(映射到接口)
注!:如果改了接口后,之前生成的代码出现错误,执行“Clear Generated Code”菜单!!!

接口
  1. [CSharpCallLua]//lua映射到接口一定要加上这个特性interfaceIPerson{string name {get;set;}int age {get;set;}voidthink();}
复制代码
Start函数
  1. IPerson p = luaenv.Global.Get<IPerson>("person");
  2.   Debug.Log(p.name);
  3.   p.name ="小李";// 通过c#更改lua中的变量
  4.   Debug.Log(p.name);
  5.   p.think();//执行lua中的方法
  6.   luaenv.Dispose();
复制代码
lua方法也可以通过以下方式来定义
  1.   person={
  2.       name="小明",
  3.           age=10
  4.   }
  5.   function person:add2(a,b) --通过:调用可以不用传递参数(),系统会自动传递当前的表
  6.       print(a+b)
  7.   end
  8.   function person.add3(self,a,b) --通过.调用必须传递自身,self不会自动赋值,我们必须通过第一个参数来传递当前的table
  9.       print(a+b)
  10.   end
复制代码
3.通过c#访问lua中的表(映射到Dictionary或者List)
Start函数
  1. ...
  2.   Dictionary<string,object> dic = luaenv.Global.Get<Dictionary<string,object>("person");foreach(var item in dic){print(item);//通过dic映射过来的值只会映射有对应键的值}
  3.   
  4.   List<object> list = luaenv.Global.Get<List<object>>("person");foreach(var item in list){print(item);/通过list映射过来的值只会映射没有对应键的值
  5.   }
  6.   luaenv.Dispose();...
复制代码
4.通过c#访问lua中的表(映射到LuaTable类)
注:这种方式好处是不需要生成代码,但也有一些问题,比如慢,比方式2要慢一个数量级,比如没有类型检查。一般情况下推荐使用第二种方式,少用第四种方式
Start函数
  1. ...LuaTable tab = luaenv.Global.Get<LuaTable>("person");print(tab.Get<string>("name"));print(tab.Get<int>("age"));
  2.   luaenv.Dispose();...
复制代码

通过c#访问lua中的全局函数(映射到delegate)
lua
  1.   function fun1()
  2.           print("fun1!")
  3.   end
  4.   
  5.   function fun2(a,b)
  6.           print(a+b)
  7.   end
  8.   
  9.   function fun3(a,b)
  10.           return a+b
  11.   end
复制代码
c#
  1. publicclassCSharpCallLuaTest:MonoBehaviour{LuaEnv luaenv =null;privatevoidStart(){
  2.           luaenv =newLuaEnv();
  3.           luaenv.DoString("require 'CSharpCallLua'");//无参数委托Action fun1 = luaenv.Global.Get<Action>("fun1");fun1();
  4.           fun1 =null;//删除c#对lua函数的引用使得lua虚拟机能顺利释放内存//传参委托Fun2 fun2 = luaenv.Global.Get<Fun2>("fun2");fun2(2,4);
  5.           fun2 =null;//传参委托带返回值Fun3 fun3 = luaenv.Global.Get<Fun3>("fun3");int res=fun3(2,4);print(res);
  6.           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);
  7.           fun4 =null;
  8.   
  9.           luaenv.Dispose();}[CSharpCallLua]//委托必须加上CSharpCallLua特性delegatevoidFun2(int a,int b);[CSharpCallLua]delegateintFun3(int a,int b);[CSharpCallLua]delegateintFun4(int a,int b,outint c,outint d);
复制代码
通过c#访问lua中的全局函数(映射到LuaFunction)
lua代码见上文
c#
  1. //通过LuaFunction映射lua方法比较耗费性能 一般不推荐使用LuaFunction luaFun = luaenv.Global.Get<LuaFunction>("fun4");object[] calls= luaFun.Call(2,5);foreach(var item in calls){print(item);}
  2. 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
  1. --需要经常访问的类,可以先用局部变量引用后访问
  2. --所有C#相关的都放到CS下即以CS开头
  3. local gameObject=CS.UnityEngine.GameObject
  4. --lua里头没有new关键字 可以拥有这种方式创建一个GameObject对象
  5. gameObject("new")
  6. --通过lua代码改变Unity中的相机名字
  7. local camera=gameObject.Find("Main Camera")
  8. --修改camera对象的名字
  9. camera.name="ChangeName"
  10. --得到camera对象的Camera组件 使用:会把当前的对象当作第一个参数传递过去
  11. --建议所有的成员方法都通过:来调用
  12. --local cameraCom=camera.GetComponent(camera,"Camera")//用.调用需要传递当前对象
  13. local cameraCom=camera:GetComponent("Camera")
  14. --摧毁相机组件
  15. gameObject.Destroy(cameraCom)
复制代码
c#
  1. privatevoidStart(){LuaEnv luaenv =newLuaEnv();
  2.         luaenv.DoString("require 'LuaCallCSharp'");
  3.         luaenv.Dispose();}
复制代码
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 09:44 , Processed in 0.087704 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表