当前位置: 首页 > news >正文

xLua学习笔记_在C#脚本中使用xLua

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测的实现的部分都以delegateinterface的方式提供,使用方可以完全和xLua解耦:由一个专门的模块负责xlua的初始化以及delegateinterface的映射,然后把这些delegateinterface设置到要用到它们的地方。

 


 

  •  自定义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     }

 

 

 

 

 

 

 

 

相关文章:

  • xLua学习笔记(三) Lua调用C#代码
  • UE4引用资源小结
  • UE4 Rendering Dependency Graph
  • 分析 UObjecBaseUtility
  • 解析PAK文件
  • UE4资源热更打包工具HotPatcher
  • Unity游戏资源逆向工具
  • UE4 Pak 文件格式
  • 更新UnrealPakViewer工具
  • UE4中Taglib使用及插件制作
  • UE4编辑器扩展踩坑血泪史
  • require函数
  • UE4 给static mesh 动态添加Socket
  • UE4 角色用Child Actor组建添加装备 这样方便随时添加,更换套装等行为
  • Unity Assets目录下的特殊文件夹名称
  • Angular2开发踩坑系列-生产环境编译
  • Angular4 模板式表单用法以及验证
  • Java-详解HashMap
  • Mybatis初体验
  • Python - 闭包Closure
  • Web标准制定过程
  • 精彩代码 vue.js
  • 前嗅ForeSpider教程:创建模板
  • 我的面试准备过程--容器(更新中)
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 终端用户监控:真实用户监控还是模拟监控?
  • 阿里云ACE认证学习知识点梳理
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • $.each()与$(selector).each()
  • (0)Nginx 功能特性
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (十)c52学习之旅-定时器实验
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转)scrum常见工具列表
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Core中Emit的使用
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • /var/lib/dpkg/lock 锁定问题
  • @SuppressLint(NewApi)和@TargetApi()的区别
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [AutoSar]BSW_OS 02 Autosar OS_STACK
  • [BZOJ4566][HAOI2016]找相同字符(SAM)
  • [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子
  • [GN] DP学习笔记板子
  • [leetcode]Symmetric Tree
  • [MYSQL]mysql常用操作命令
  • [Oh My C++ Diary]内联函数
  • [PAT练级笔记] 44 Basic Level 1044 火星数字
  • [Python] 字典操作及方法总结
  • [QT] TCP协议演示
  • [Ruby on Rails系列]4、专题:Rails应用的国际化[i18n]
  • [Socket]Unix socket 运行权限问题
  • [spark] DataFrame 的 checkpoint