這幾天整了一下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#甜味十足的語法糖,現在要轉換成這種死板的語法,實在是有些不適應。