tolua学习

LuaInterface是一个实现lua和微软.Net平台的CLR混合编程的开源库。使得lua脚本可以实例化CLR对象、访问属性、调用方法、甚至使用lua函数来处理事件。

tolua基于LuaInterface。tolua在LuaInterface基本形式的基础上,使代码更简洁,提供了对Unity的支持。两者最大区别在于:LuaInterface中lua访问CLR需要运行时反射,tolua则是通过预先生成wrap进行访问。

1.Unity的tolua插件使用

将类名添加到CustomSetting.cs中,点击菜单栏的Clear wrap files,然后点击Generate All。

会产生如下变化

  • 自动生成一个Wrap文件

  • 会在LuaBinder.cs文件中添加Warp文件的注册

1.1lua中调用C#方法

实际上是把参数压栈,调用了Wrap文件中的静态方法,然后在该方法中再执行C#的部分。

--调用类的静态方法
local go = UnityEngine.GameObject.Find("LuaScene")
 
--调用对象的成员方法,注意是用冒号调用,相当于把自身作为第一个参数压栈了。
local access = go:GetComponent("CSharpAccess")

1.2C#中调用lua方法

通过luaState执行脚本或者获得函数。

void Start() 
{
    luaState = new LuaState();  // 启动1:创建tolua提供的LuaState对象。              
    luaState.Start();           // 启动2:虚拟机初始化。
    LuaBinder.Bind(luaState);   // 启动3:Lua-c#中间层wrap文件们分别向虚拟机注册自己。
     
    //执行lua脚本或者lua函数
    luaState.DoFile("Main.lua");
    luaState.Require("Main.lua");
     
    LuaFunction  main = luaState.GetFunction("Main");
    main.Call();
    main.Dispose();
    main = null;    
 
}
 

2.tolua机制

2.1 C#调用原生代码

DllImport函数,功能是提供从非托管DLL导出的函数的必要调用信息。toluaUnity项目中提供了一个LuaDLL.cs,在C#中又对tolua.dll进行了一次封装。

2.2 数据准备

tolua启动的时候会注册Wrap文件,在luaState中创建好了模块和类,这些函数的背后执行了原生代码。

//LuaBinder.cs
L.BeginModule("UnityEngine");
 
L.BeginClass(typeof(UnityEngine.Component),  typeof(UnityEngine.Object));
L.RegFunction("GetComponent",  GetComponent);
L.RegVar("transform",  get_transform, null);
L.RegVar("gameObject",  get_gameObject, null);
L.RegVar("tag",  get_tag, set_tag);
L.EndClass();
 
L.EndModule();

BeginModule(null)代表当前命名空间是global全局域,而BeginModule(“UnityEngine”)则代表后面都注册到_G[“UnityEngine”]表中。

BeginClass相当于是类的注册。

  • 创建了一个叫Component的table,并复制一份压入栈中,有两个table;

  • 栈顶table设置userdata、.name、__index、__newindex等;

  • 弹出栈顶table,并将其设置为第二个table的元表;

  • RegFunction注册函数,将注册的方法转换成供平台使用的之神,传递到C中生成可以供lua使用的LuaCSFunction函数,最终生成闭包,存到当前栈顶table中。

2.3 lua调用C#的对象和方法

2.3.1对象

实例存储在C#中LuaState的ObjectTranslator中,lua中的变量只是一个持有该C#实例索引位置的fulluserdata,并没有直接对C#实例进行引用。lua调用时会把fulluserdata压栈,C#层取到索引后,可以通过ObjectTranslator.GetObject(intudata)获得对象。

2.3.2方法

静态方法调用

直接从类的表里搜索函数。

成员方法调用
  • 在lua中对象实际上是userdata,类的table是它的元表,所以从类的table中搜索函数。因为是冒号调用的,所以把自己作为第一个参数和其他参数一起压栈。

  • 调用Wrap中的函数,根据参数个数进行重载。从栈中获取参数,调用的对象可以通过userdata的索引从ObjectTranslator中获取,并执行C#中的代码。

2.4 对Vector3的优化

原因是boxing(装箱)和unboxing(拆箱)。Vector3(栈)转为object类型需要boxing(堆内存中),object转回Vector3需要unboxing,使用后释放该object引用,这个堆内存被gc检测到已经没引用,释放该堆内存,产生一个gc内存。

关于结构体,目前只支持一些特定的结构体,需要在lua中对应一份实现(Assets\ToLua\Lua目录中)。例如:Vector3对应的实现目录是Assets\ToLua\Lua\UnityEngine\Vector3.lua。所以说tolua用lua重新实现了Vector3。

2.4.1 tolua创建Vector3

Vector3.New(x,  y, z)

toLua并没有跟UnityC#交互。

2.4.2 C#传Vector3到lua

  • C# UnityEngine_TransformWrap.get_position;调用ToLua.Push

  • 把Vector的x,y,z三个值拆开传过去;

  • 在lua创建一个lua table,把x,y,z设置为对应字段。

2.4.3 lua传Vector3到C#

  • 从栈中去除对应table的x,y,z;

  • C# new一个Vector3,将x,y,z赋值到Vector3。

3.参考资料

【ToLua】源码学习总结 https://zhuanlan.zhihu.com/p/320575488

tolua之wrap文件的原理与使用 https://www.cnblogs.com/blueberryzzz/p/9672342.html

ToLua:逐行分析源码,搞清楚Wrap文件原理 https://blog.csdn.net/qq_28820675/article/details/106864636

ToLua源码分析:启动流程 https://blog.csdn.net/lodypig/article/details/60160020

tolua#代码简要分析 https://www.cnblogs.com/ghl_carmack/p/6720500.html

Unity中xLua与toLua对Vector3的优化 https://www.jqhtml.com/53934.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值