tolua踩坑(一)

這幾天整了一下lua,打算以此增加demo的靈活度,爲以後實現熱更新做準備。框架採用tolua,這框架該有的都有,但用起來就是沒有Spring等等大型的框架好用,且其中的坑比之Spring有過之而無不及,簡直夢迴初學Spring的時候,一個問題能搗鼓一天,最後發現其實簡單的不得了。這個系列的博客就來記錄下我踩的tolua坑,避免以後再掉到相同的坑裏。


1. 句號(.)和冒號(:)

我記得之前看見有人說過這個事,但我真正遇到的時候卻忘了這茬。
tolua在向LuaState注入我們指定的類型後,調用方式一般是和在C#中一樣的,類似於

instance = Thunder.UI.BaseUi()

這樣的調用(爲什麼Markdown連lua的高亮都沒有??果然lua還是太小衆了麼,還是Notepad兼濟天下),一般來說沒什麼問題,命名空間、類、屬性等都是和C#一樣通過句號(.)來獲取,但是方法就不一樣了,我們知道,方法是有靜態和非靜態之分的,通過static修飾符來區分。C#、Java等語言調用時都一視同仁,使用(.)來獲取。lua則比較標新立異,非靜態用(:),靜態則用(.)。舉個例子:

namespace Thunder.Vehicle
{
	public class BattleShip
	{
		public static void Shoot()
		{
			Debug.Log("Shoot");
		}
		
		public void Person Invade()
		{
			Debug.Log("Create Person");
			return new Person()
		}
	}
	
	public class Person
	{
		public static void Melee()
		{
			Debug.Log("Melee!!");
		}
	}
}

這個類被注入了lua的環境,那麼需要按如下方式調用:

battleShip = Thunder.Vehicle.BattleShip()
battleShip.Shoot()
battleShip:Invade().Melee()

-- Output:
--
-- Shoot
-- Create Person
-- Melee!!

可見BattleShip對它的靜態方法Shoot使用(.)調用,對非靜態方法Invade使用(:)調用。返回的Person使用(.)調用它的靜態方法Melee。此外Thunder.Vehicle.BattleShip也使用(.)來進行命名空間的選擇。


2. 泛型

tolua對於泛型的支持可謂是十分稀爛,不過對於lua來說,或許本來也就沒有什麼好的方法來讓它適配泛型,因爲它本身就是弱類型的語言。但又要與C#這種強類型的語言進行交互,還是有處理這方面的必要的。先提個需求,看看tolua怎麼處理這事:

有戰艦(BattleShip)和人類(Person)兩種對象,我們需要讓戰艦通過某種方式接收士兵。具體的實現方式是,在lua文件中定義一個方法,返回人類的list。類的定義如下:

namespace Thunder.Entity
{
	public class BattleShip
    {
        public LuaState luaState;

        private List<Person> _Marine;

        public void ReceiveSoldiers()
        {
            _Marine = luaState.Invoke<List<Person>>("ReceiveSoldiers",true);
        }
    }

    public class Person
    {
        public int Id;

        public Person(int id)
        {
            Id = id;
        }
    }
}

重點,需要向CustomSettings.cs中的customTypeList添加:

_GT(typeof(System.Collections.Generic.List<Person>)),
_GT(typeof(Thunder.Entity.BattleShip)),
_GT(typeof(Thunder.Entity.Person))

泛型類型是不能單獨使用的,需要按照特例來添加。這就使得泛型這種優雅的語法完全遲鈍化,不過這也是沒辦法的事。接下來是lua:

function ReceiveSoldiers()
    soldiers = System.Collections.Generic.List_Thunder_Entity_Person()
    for id=0,300,1 do
        soldiers:Add(Thunder.Entity.Person(id))
    end
    return soldiers
end

可以看見,lua創建list對象時使用的名稱是List_Thunder_Entity_Person,看到這裏,大家應該很快就能發現:在lua中調用tolua包裝好的泛型類,需要將(.)轉換爲(_),如果有多個類型參數,需要依次排列,順序不能顛倒,而且需要使用FullName,也就是包含了namespace的名稱,例如List_Thunder_Entity_Person_Thunder_Entity_BattleShip,不能省略namespace。
鑑於這種情況,我的解決方案就是設計接口的時候,能不用泛型就不用,儘量使用傳統的語法來完成需求。不過喫慣了C#甜味十足的語法糖,現在要轉換成這種死板的語法,實在是有些不適應。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章