读一读

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);
		}
	}
}


  1. 通过WWW加载一个文本文件,里面的内容表达的是资源的版本号

  2. 版本号不同时,去下载远程的assetbundle,相同时,下载本地的assetbundle

  3. 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 索引的形式设置和获取到变量,给予相应的类型