网站建设公司推荐q479185700顶上,如何将自己做的网站放到网上去,携程做旅游的网站,山西通州集团网站建设ToLua 是一个用于在 Unity 中为 Lua 提供 C# 语言绑定的框架。通过 ToLua#xff0c;你可以方便地将 C# 代码暴露给 Lua 脚本#xff0c;并在 Lua 脚本中调用 C# 类、方法和属性。
更新流程
原理#xff1a;使用AssetBundle进行资源的更新#xff0c;而由于lua运行时才编…ToLua 是一个用于在 Unity 中为 Lua 提供 C# 语言绑定的框架。通过 ToLua你可以方便地将 C# 代码暴露给 Lua 脚本并在 Lua 脚本中调用 C# 类、方法和属性。
更新流程
原理使用AssetBundle进行资源的更新而由于lua运行时才编译的特性所以lua文件也可以被看成是一种资源文件与fbx、Image等一样可以打进ab包中
流程
游戏运行时从服务器下载files.txt清单文件,与本地的files.txt清单文件进行对比。如果新下载的files里面的md5值与本地files的md5值不一样,或者本地清单里没有对应文件那么就从服务器下载AB包然后解压进行初始化
LuaState
C#能调用lua的原理就是创建了一个lua虚拟机LuaState封装了对lua 主要数据结构 lua_State 指针的各种堆栈操作。
去反射
旧版本中lua调用C#函数是基于反射的而现阶段是基于去反射意思就是把所有的c#类的public成员变量、成员函数都导出到一个相对应的Wrap类中。而这些成员函数通过特殊的标记映射到lua的虚拟机中当在lua中调用相对应的函数时候直接调用映射进去的c# wrap函数然后再调用到实际的c#类完成调用过程
Lua虚拟栈 C#会告诉虚拟机传入的参数和需要返回的参数然后虚拟机开始访问栈从栈中取出对应函数传送给Lua编译器。然后lua程序调用Lua文件全局表Global table查找对应函数然后将返回参数入栈C#再从栈中读取数据。
可以按1N的顺序从栈底向上也可以从-1-N从栈顶向下栈中可以存储任何数据函数、table等空的位置用nil表示
前置准备
使用Tolua的相关类和方法都需要调用命名空间LuaInterfaceLuaState.Start 需要在tolua代码加载到内存后调用。如果使用assetbunblde加载lua文件调用Start()之前assetbundle必须加载好。
调用lua脚本必须先创建一个lua虚拟机 一般对于客户端推荐只创建一个LuaState对象。如果要使用多State需要在Unity中设置全局宏 MULTI_STATE创建步骤为
LuaState lua new LuaState();加载脚本
重要方法lua.AddSearchPath 通过此方法添加lua文件的路径只有添加了文件路径之后在该路径上的lua文件才可以被读取。这样DoFile跟Require函数可以只用文件名,无需写全路径。
在C#中运行一段lua脚本最简单的方法就是lua.DoString该方法声明如下
public object[] DoString(string chunk, string chunkName LuaState.DoString)注意dofile需要扩展名, 可反复执行, 后面的变量会覆盖之前的DoFile加载的变量这里加载了就会从开始逐句执行。
LuaState.Require
public void Require(string filename)因为Require 读取文件是会检查该文件是否被加载过如果被加载过则直接返回一个索引否则则加载并返回一个索引 使用完lua虚拟机之后记得要销毁具体操作如下 先进行lua虚拟机的判空具体做法为lua.CheckTop析构掉lua虚拟机具体做法为lua.Dispose
C#调用lua函数
调用lua方法
我们可以把lua中的函数看成一个对象在虚拟机初始化完成后加载对应的lua文件接着需要创建一个LuaFunction类型的对象来表示这个lua函数可以通过调用lua.GetFunction(方法名); 来获取对应的函数对象
获取了之后就需要在C#中调用了主要方式有两种
直接调用LuaFunction类型的对象的func.Call 方法完整声明为
public object[] Call(params object[] args)这种调用方法比较简单但是有一个缺点lua对象的内存无法被自动释放所以当使用完这个lua函数对象之后我们需要手动的调用LuaFunction类型的对象的func.Dispose();方法释放掉垃圾内存否则会造成内存泄漏
不过选择都采用的是委托的方式需要先进行DelegateFactory.Init()
int num luaFunc.Invokeint,int(arg);或者是
Funcint, int Func luaFunc.ToDelegateFuncint, int();
num Func(123456);如同案例当中的CallFunc()
int CallFunc()
{ luaFunc.BeginPCall(); luaFunc.Push(123456);luaFunc.PCall(); int num (int)luaFunc.CheckNumber();luaFunc.EndPCall();return num;
}首先我们必须先以func.BeginPCall;开始通过func.Push(参数)来给方法传参–通过众多重载函数来解决参数转换的gc然后需要通过func.PCall();来运行接着通过对应的func.Checkxxx()方法来获取返回值,最后通过func.EndPCall();结束–清楚函数调用导致的堆栈变化。整个流程比较繁琐且不易封装不过优点是不会有垃圾内存所以不用手动释放GC。
获取lua中的变量
创建全局变量
在lua虚拟机创建完成且初始化完毕调用Start方法之后可以直接声明一个lua虚拟机的全局变量:
LuaState lua new LuaState();
lua.Start();
lua[Objs2Spawn] 5;获取全局变量格式是相同的这点和lua相同没有就创建否则就读取。值得注意的是对于获取的函数需要强制转换为LuaFunctionLuaFunction func lua[TestFunc] as LuaFunction;
获取与创建lua的table
通过调用虚拟机的方法lua.GetTable 来获取lua中的table用LuaTable类型来储存lua中的Table通过调用Luatable的成员方法table.AddTable来创建lua中的table , 除了通过虚拟机的GetTable方法访问之外直接通过 LuaTable 型变量按字典的类似方法也可以调用table
LuaTable table1 lua.GetTable(varTable);
Debug.Log(Read VarTable from lua name:{0}, table1[map.name]);//会将map.name作为整体识别为键,值为nil不会有任何输出
table1[map.name] new;// table字符串只能为key,现在为“new”
LuaTable table2 (LuaTable)table[newmap];对于lua元表也能使用LuaTable的GetMetaTable()方法来获取
对于变量的获取有一点值得注意
如同注释中的那样[]中的string会作为整体。lua语法中如果有一个table A那么A.x代表的是A[“x”],表示的是由字符串 “x”索引的表 而a[x]表示的是变量x对应的值索引的表
a {}
x y
a[x] 10
a.x --nil 字段“x”的值未定义
a.y --10, 字段“y”的值因此如果想要C#正确获取的话需要像下面这样
LuaTable table lua.GetTable(varTable);
LuaTable map (LuaTable)table[map];
Debugger.Log(Read varTable from lua, name: {0}, map[name]);对LuaTable类型的变量在使用完后需要手动释放内存否则会因为内存未自动释放造成内存泄漏具体方法为调用LuaTable对象的方法table.Dispose();
GameObject
private string script local GameObject UnityEngine.GameObject local ParticleSystem UnityEngine.ParticleSystem local go GameObject(go)go:AddComponent(typeof(ParticleSystem))local node go.transformnode.position Vector3.one print(gameObject is: ..tostring(go)) GameObject.Destroy(go, 2) ;LuaState lua null;void Start()
{ lua new LuaState();lua.LogGC true;lua.Start();LuaBinder.Bind(lua);lua.DoString(script);
}void Update(){lua.CheckTop();lua.Collect();
}LuaBinder.Bind(); ——该方法需要传入一个 LuaState 类型参数。该方法会将 C# 代码中定义的类、方法、属性等绑定到该 Lua 模块中。这样Lua 脚本就可以调用 C# 代码中定义的函数和属性而 C# 代码也可以通过 Lua 脚本调用 Lua 中的函数和属性。
lua.Collect();——垃圾回收, 对于被自动gc的LuaFunction, LuaTable, 以及委托减掉的LuaFunction, 延迟删除的Object之类。等等需要延迟处理的回收, 都在这里自动执行
lua调用C#函数
如同 案例中的那样
local ParticleSystem UnityEngine.ParticleSystem
local GameObject UnityEngine.GameObjectlocal
go GameObject(go)
go:AddComponent(typeof(ParticleSystem))
local node go.transform
node.position Vector3.one
print(gameObject is: ..tostring(go))对于UnityEngine下的一部分方法lua中可以直接引用。
自定义脚本
对于自己实现的脚本比较麻烦首先需要调用 LuaBinder.Bind(LuaState lua)
其次需要将自定义的类写入CustomSetting.cs文件中你将你的自定义类加入到customTypeList数组中的末尾如果是静态类就还需加入staticClassTypes中。然后依次点击Lua菜单中的Clear wrap files 和Gen All
自定义委托
只要需要使用到delegate字段都要调用一次DelegateFactory.Init()如果有自定义的委托还是要添加到CustomSetting.cs中的customDelegateList
如何给按钮动态添加监听事件 首先我们可以定义一个LuaHelper的静态类在其中实现一个AddButtonClick的静态函数NGUI中给按钮添加事件代码示例EventDelegate.Add(UIButton.onclick, Call call)
public static void AddButtonClick(GameObject g,LuaFunction callback)
{EventDelegate.Add(g.GetComponentUIButton().onClick, callback.Call);
}在lua代码中只需找到对应的游戏物体
local helper LuaHelper
local btn UnityEngine.GameObject.Find(Button)local function Onclick()print(OnClick)
end
helper.AddButtonClick(btn,Onclick)Lua调用C#的规范就是不在Start周期函数中去做初始化而是包装好初始化相关的函数在lua中获取该函数在调用
获取C#数组元素
lua想要访问C#数组有几种方法
通过下标访问——这与C#中一致而且还可以通过array.Length获取数组大小通过迭代器访问——array:GetEnumerator()获取数组的迭代器通过iter.Current获得当前的迭代器所指向的元素值通过iter:MoveNext()将迭代器所指位置移至下一个调用 array:ToTable() 实现将数组对象转化为对应的lua中的Table表的形式进行访问注意lua数组下标从0开始
C#中获得lua函数的返回值可以通过func.Checkxxx()来获得
比如
double arg1 func.CheckNumber();//获得func函数double类型的返回值
string arg2 func.CheckString();//获得func函数string类型的返回值
// 调用通用函数时需要转换类型避免拆成多个参数
object[] objs func.Invoke((object)array);
if (objs ! null)
{Debugger.Log(return is {0} {1} {2}, objs[0], objs[1], objs[2]);
}ToLua框架UML