例子1
展示了最小的tolua#环境,以及执行一段lua代码操作代码如下:
LuaState封装了对lua 主要数据结构 lua_State 指针的各种堆栈操作。
一般对于客户端,推荐只创建一个LuaState对象。如果要使用多State需要在Unity中设置全局宏 MULTI_STATE
- LuaState.Start 需要在tolua代码加载到内存后调用。如果使用assetbunblde加载lua文件,调用Start()之前assetbundle必须加载好
- LuaState.DoString 执行一段lua代码,除了例子,比较少用这种方式加载代码,无法避免代码重复加载覆盖等,需调用者自己保证。第二个参数用于调试信息,或者error消息(用于提示出错代码所在文件名称)
- LuaState.CheckTop 检查是否堆栈是否平衡,一般放于update中,c#中任何使用lua堆栈操作,都需要调用者自己平衡堆栈(参考LuaFunction以及LuaTable代码), 当CheckTop出现警告时其实早已经离开了堆栈操作范围,这是需自行review代码。
- LuaState.Dispose 释放LuaState 以及其资源。
- 1:使用Tolua的相关类及方法都需要调用命名空间LuaInterface
2:调用lua脚本必须要先创建一个lua的虚拟机,而创建的步骤就是LuaState lua = new LuaState();, 创建一个LuaState型的对象,这个就是lua的虚拟机,后面的lua的与C#的交互全部依仗这个东西。
3:lua中直接运行一段lua脚本最简单的方法就是 lua.DoString, 该方法声明如下:
public object[] DoString(string chunk, string chunkName = "LuaState.DoString")
4:使用完lua虚拟机之后记得要销毁,具体操作如下:先进行lua虚拟机栈的判空,具体对应的就是lua.CheckTop , 然后就是析构掉lua虚拟机,具体方法为lua.Dispose
注意: 此例子无法发布到手机
例子2
展示了dofile跟require的区别, 代码如下:
tolua#DoFile函数,跟lua保持一致行为,能多次执行一个文件。tolua#加入了新的Require函数,无论c#和lua谁先require一个lua文件, 都能保证加载唯一性
- LuaState.AddSearchPath 增加搜索目录, 这样DoFile跟Require函数可以只用文件名,无需写全路径
- LuaState.DoFile 加载一个lua文件, 注意dofile需要扩展名, 可反复执行, 后面的变量会覆盖之前的DoFile加载的变量
- LuaState.Require 同lua require(modname)操作, 加载指定模块并且把结果写入到package.loaded中,如果modname存在, 则直接返回package.loaded[modname]
- LuaState.Collect 垃圾回收, 对于被自动gc的LuaFunction, LuaTable, 以及委托减掉的LuaFunction, 延迟删除的Object之类。等等需要延迟处理的回收, 都在这里自动执行
注意: 虽然有文件加载,但此例子无法发布到手机, 如果ToLua目录不在/Assets目录下, 需要修改代码中的目录位置
例子3 LuaFunction
展示了如何调用lua的函数, 主要代码如下:
tolua# 简化了lua函数的操作,通过LuaFunction封装(并缓存)一个lua函数,并提供各种操作, 建议频繁调用函数使用无GC方式。
- LuaState.GetLuaFunction 获取并缓存一个lua函数, 此函数支持串式操作, 如"test.luaFunc"代表test表中的luaFunc函数。
- LuaState.Invoke 临时调用一个lua function并返回一个值,这个操作并不缓存lua function,适合频率非常低的函数调用。
- LuaFunction.Call() 不需要返回值的函数调用操作
- LuaFunction.Invoke() 有一个返回值的函数调用操作
- LuaFunction.BeginPCall() 开始函数调用
- LuaFunction.Push() 压入函数调用需要的参数,通过众多的重载函数来解决参数转换gc问题
- LuaFunction.PCall() 调用lua函数
- LuaFunction.CheckNumber() 提取函数返回值, 并检查返回值为lua number类型
- LuaFunction.EndPCall() 结束lua函数调用, 清楚函数调用造成的堆栈变化
- LuaFunction.Dispose() 释放LuaFunction, 递减引用计数,如果引用计数为0, 则从_R表删除该函数
注意: 无论Call还是PCall只相当于lua中的函数'.'调用。
请注意':'这种语法糖 self:call(...) == self.call(self, ...)
c# 中需要按后面方式调用, 即必须主动传入第一个参数self
例子4
展示了如何访问lua中变量,table的操作
- luaState["Objs2Spawn"] LuaState通过重载this操作符,访问lua _G表中的变量Objs2Spawn
- LuaState.GetTable 从lua中获取一个lua table, 可以串式访问比如lua.GetTable("varTable.map.name") 等于 varTable->map->name
- LuaTable 支持this操作符,但此this不支持串式访问。比如table["map.name"] "map.name" 只是一个key,不是table->map->name
- LuaTable.GetMetaTable() 可以获取当前table的metatable
- LuaTable.ToArray() 获取数组表中的所有对象存入到object[]表中
- LuaTable.AddTable(name) 在当前的table表中添加一个名字为name的表
- LuaTable.GetTable(key) 获取t[key]值到c#, 类似于 lua_gettable
- LuaTable.SetTable(key, value) 等价于t[k] = v的操作, 类似于lua_settable
- LuaTable.RawGet(key) 获取t[key]值到c#, 类似于 lua_rawget
- LuaTable.RawSet(key, value) 等价于t[k] = v的操作, 类似于lua_rawset
例子5 协同一
展示了如何使用lua协同, lua 代码如下:
c#代码如下:
- 必须启动LuaLooper驱动协同,这里将一个lua的半双工协同装换为类似unity的全双工协同
- fib函数负责计算一个斐那波契n
- coroutine.start 启动一个lua协同
- coroutine.wait 协同中等待一段时间,单位:秒
- coroutine.step 协同中等待一帧.
- coroutine.www 等待一个WWW完成.
- tolua.tolstring 转换byte数组为lua字符串缓冲
- coroutine.stop 停止一个正在lua将要执行的协同