tolua是Unity静态绑定lua的一个解决方案,它通过C#提供的反射信息分析代码并生成包装Wrap的类。它是一个用来简化在C#中集成lua的插件,可以自动生成用于在lua中访问Unity的绑定代码,并把C#中的常量、变量、函数、属性、类以及枚举暴露给lua。它是从cstolua演变过来的。从它的名字看出,它是集成了原来的tolua代码通过二次封装了一个C#与tolua(c)的一个中间层。
public string url = "file://F:/testAsset/";//假装是远程服务器 void Awake(){ StartCoroutine (Load()); } IEnumerator Load(){ using(WWW www = new WWW(url+"1.txt")){ yield return www; //版本对不上,进行下载,不然加载本地 using(WWW www2 = WWW.LoadFromCacheOrDownload(url+"1.assetbundle",Int32.Parse(www.text))){ yield return www2; AssetBundle asset = www2.assetBundle; //获取图片,更改按钮的资源 Sprite sprite = asset.LoadAsset<Sprite>("1"); Image img = GameObject.Find ("Button").GetComponent<Image> (); img.sprite = sprite; //加载代码 运行lua代码 TextAsset luaString = asset.LoadAsset<TextAsset> ("1Lua"); LuaState lua = new LuaState (); lua.Start(); LuaBinder.Bind (lua); lua.DoString (luaString.text); LuaFunction func = lua ["changButtonText"] as LuaFunction; Text txt = GameObject.Find ("Text").GetComponent<Text> (); func.BeginPCall (); func.Push (txt); func.PCall (); func.EndPCall (); func.Dispose (); lua.CheckTop (); lua.Dispose (); asset.Unload (false); } } }
通过WWW加载一个文本文件,里面的内容表达的是资源的版本号
版本号不同时,去下载远程的assetbundle,相同时,下载本地的assetbundle
assetbundle的资源中lua代码使用txt文件保存,使用TextAsset.string获取
使用www下载到AssetBundle后,通过AssetBundle对象获取文本文件TextAsset时,发现text属性内容为空,但是文本文件确实存在内容。原来是Unity的资源都是要通过它自己处理的,就是要经过导入这个过程,而我是直接在目录文件夹中创建的(没有重启Unity),所有识别不了。
.txt后缀结尾的,使用TextAsset的text获取。.bytes后缀结尾的,使用TextAsset的bytes属性获取。
有些资源,Unity不支持的是不能够打包到AssetBundle里面的,例如后缀为.lua的文件,我设置了它的assetbundle名字和后缀,导出的时候,在文件列表中却发现没有它,改为txt文件就可以了。
private string luaString = @" local GameObject = UnityEngine.GameObject --获取类 local ParticleSystem = UnityEngine.ParticleSystem; --粒子组件 go = GameObject('go') --创建游戏物体 go:AddComponent(typeof(ParticleSystem)) --添加组件 local trsn = go.transform --获取Transform组件 trsn.position = Vector3.one --赋值属性 GameObject.Destroy(go,2) --2秒后移除物体 "; private LuaState lua; // Use this for initialization void Start () { lua = new LuaState (); lua.Start (); lua.LogGC = true; LuaBinder.Bind (lua); lua.DoString (luaString); } void Update () { lua.CheckTop (); lua.Collect ();//专业回收垃圾 } void Destroy(){ lua.Dispose (); }
Update中的lua.Collect(),如果没有了它,lua代码中Destroy了也没有效果
private string luaString = @" function test(dic) iter = dic:GetEnumerator() while iter:MoveNext() do --遍历字典 print('key'.. iter.Current.Key .. 'value' .. iter.Current.Value) end keys = dic.Keys --获取字典的键值数组 values = dic.Values --获取字典值的数组 iter = values:GetEnumerator() while iter:MoveNext() do print(iter.Current) end local hehe,val = dic:TryGetValue(1,nil) --尝试获取键的值,第一个返回状态,第二个才是值 print(val) dic:Remove(2) --移除键值为2的元素 --跟C#字典的操作一样 end "; private Dictionary<int,string> dicc = new Dictionary<int, string>(); void Start () { LuaState lua = new LuaState (); lua.Start (); lua.DoString (luaString); dicc.Add (1, "hello"); dicc.Add (2, "world"); LuaFunction func = lua ["test"] as LuaFunction; func.BeginPCall (); func.Push (dicc); func.PCall (); func.EndPCall (); foreach (var item in dicc) { Debug.Log (item.Value); //只输出了hello } func.Dispose (); lua.CheckTop (); lua.Dispose (); }
private string luaString = @" function tset(array) --array是c#传进来的数组 len = array.Length --获取数组的长度 for i=0,len-1,1 do print(array[i]) --和c#数组一样的下标方式访问 end arrTable = array:ToTable() for i=1,#arrTable do print(arrTable[i]) end iter = array:GetEnumerator() while iter:MoveNext() do print(iter.Current) end print(array:IndexOf(6)) end "; // Use this for initialization void Start () { LuaState lua = new LuaState (); lua.Start (); lua.DoString (luaString); int[] vals = { 1, 3, 5, 4, 6, 1 }; LuaFunction func = lua ["tset"] as LuaFunction; func.BeginPCall (); func.Push (vals); func.PCall (); func.EndPCall (); func.Dispose (); lua.Dispose (); func = null; lua = null; }
这里有三种遍历的方式,传入的c#数组,直接安装c#的数组那般使用就行了
也可以转换成Table,还有一个更灵活的GetEnumberator()方法
IndexOf()方法查找元素的下标,从0开始的(C#)
其实好像跟协程一样的写法
private string luaString = @" function test(len) print(len) for i=1,10,1 do coroutine.yield(i*10) end end function start() co = coroutine.create(test) --创造线程(协成?) return co end "; // Use this for initialization void Start () { LuaState lua = new LuaState (); lua.Start (); lua.DoString (luaString); LuaFunction func = lua ["start"] as LuaFunction; //func.BeginPCall (); //func.PCall (); //LuaThread thread = func.CheckLuaThread (); 通过CheckLuaThread()获取返回值 //func.EndPCall (); LuaThread thread = func.Invoke<LuaThread>(); //通过Invoke获得线程返回值 thread.name = "test"; //设置线程的名称,应该使用于区别的 for (int i = 0; i < 10; i++) { int ret; thread.Resume (10, out ret); //继续方法,传参和接收返回值 Debug.Log (ret); } thread.Dispose (); func.Dispose (); lua.Dispose (); thread = null; func = null; lua = null; }
private string luaString = @" function cor() print('coroutine start') coroutine.wait(5) --等待几秒 print('5s ago') print('frameCount:' .. Time.frameCount) coroutine.step() --等待一帧 print('frameCount:' .. Time.frameCount) local www = UnityEngine.WWW('http://www.baidu.com') coroutine.www(www) --等待www响应 local s = tolua.tolstring(www.bytes) print(s:sub(1,128)) end local c = nil function testCor() c = coroutine.start(cor) --开始协成 end function stopCor() if c ~= nil then coroutine.stop(c) --停止协成 end end "; private LuaState lua; private LuaLooper looper; private LuaFunction func; // Use this for initialization void Awake () { lua = new LuaState (); lua.Start (); // 不执行绑定无法使用Wrap的函数,就是GameObject等Unity的内置类 LuaBinder.Bind (lua); // 添加了这个组件后,它会在c#每一帧驱动lua的协同完成所有的协同功能,这里的协同已经不单单是lua自身功能,而是tolua#模拟unity的所有的功能. looper = gameObject.AddComponent<LuaLooper> (); looper.luaState = lua; //指定虚拟机 lua.DoString(luaString); func = lua.GetFunction("testCor"); func.Call (); LuaFunction stopFunc = lua ["stopCor"] as LuaFunction; stopFunc.Call (); stopFunc.Dispose (); } void Destroy(){ //擦屁股操作 func.Dispose (); looper.Destroy (); lua.CheckTop (); lua.Dispose (); func = null; looper = null; lua = null; }
private string luaString = @" print(a) b = 'hello' c = {} c.id = 16485 function test() print('hehe') end "; // Use this for initialization void Start () { LuaState lua = new LuaState (); lua.Start (); lua["a"] = "这是我C#传过去的"; lua.DoString (luaString); Debug.Log (lua ["b"]); LuaTable t = lua ["c"] as LuaTable; Debug.Log (t.GetStringField("id")); t.Dispose (); LuaFunction func = lua ["test"] as LuaFunction; func.Call (); func.Dispose (); lua.CheckTop (); lua.Dispose (); }
好像没什么好说的,都是通过LuaState 索引的形式设置和获取到变量,给予相应的类型