對於手機游戲,如果可以在線更新以實現bug修復、新功能添加等等,其好處自不必多說。
通過C#的反射機制,也可以實現某種程度上的腳本級更新,具體可以參考
http://docs.unity3d.com/Documentation/Manual/scriptsinassetbundles.html
但其中也明確指出了在iOS上不支持反射。所以很自然的,想到使用Lua、Python等腳本語言來解決需求。撇開Python不講(感興趣的可以搜索UniPython),來看Lua。
因為Lua本身使用C語言實現,具有良好的跨平台特性,但我們使用C#來作為主要開發語言,要實現與Lua的混合開發,最好是有一個C#版的Lua。萬能的google的幫我找到了UniLua(https://github.com/xebecnan/UniLua),特別感謝其作者xebecnan。PS:xebecnan貌似是雲風(雲風BLOG)團隊的,當看到UniLua是國人實現的,且雲風的Unity3d項目也在使用時,便立刻決定試一下:)
在現在這個項目之前,幾乎沒有任何的Lua使用經驗,完全是從開始。國內關於Lua的書籍和資料貌似都很少,書的話官方的《Lua程序設計》必讀,《Lua游戲開發實踐指南》也可以快速翻一翻。個人覺得有用的資源還有:
官方的參考手冊-居家旅行必備:http://www.lua.org/manual/5.2/
簡明教程 http://coolshell.cn/articles/10739.html
Lua與C++的混合編程入門 http://blog.csdn.net/jason3/article/details/5653487
關於如何在Unity3d中使用UniLua,wiki上面已經講的非常清晰了。其中也講到了如何在Lua中調用C#,不過僅給出了調用靜態成員函數的示例,而我僅在此記錄一下如何在Lua調用C#中的非靜態成員函數。
現有C#中的People類如下
1 public class People 2 { 3 public People(int age) 4 { 5 Age = age; 6 } 7 8 public int Age 9 { 10 get; 11 set; 12 } 13 14 public bool IsYounger(People other) 15 { 16 return (Age < other.Age); 17 } 18 }
如何在lua中調用People的成員函數IsYounger?
1. 如何訪問C#的對象:使用 light userdata,即使用UniLua提供的 PushLightUserData() 和 ToUserData()
2. 如何訪問C#的成員函數:主要是利用PushCSharpFunction() 接口,但過程略麻煩一些。
2.1 將C#類中的成員函數都封裝為靜態成員函數(后附示例代碼)
2.2 將上面的靜態成員函數設置為lua的全局變量,以在lua中調用
示例代碼:
1 public class PeopleLuaWrapper 2 { 3 const string CLASS_NAME = "People"; 4 5 public static void RegisterCSharpMethod(ILuaState lua) 6 { 7 lua.NewTable(); 8 int method_table = lua.GetTop(); 9 10 lua.PushString("IsYounger"); 11 lua.PushCSharpFunction(IsYounger); 12 lua.SetTable(method_table); //將函數設置為table的一個元素 13 14 lua.SetGlobal(CLASS_NAME); //設置名為CLASS_NAME的全局表 15 } 16 17 //! 將原成員函數重新封裝為靜態成員函數 18 private static int IsYounger(ILuaState lua) 19 { 20 People invoker = (People)lua.ToUserData(1); //獲取成員函數的調用者 21 People other = (People)lua.ToUserData(2); //獲取成員函數的參數 22 lua.Pop(2); 23 24 bool is_younger = invoker.IsYounger(other); 25 lua.PushBoolean(is_younger); //將函數結果壓棧 26 27 return 1; 28 } 29 }
lua中調用C#成員函數:
1 local function Lua_IsYounger(pa, pb) 2 is_younger = People.IsYounger(pa, pb) 3 return is_younger 4 end 5 6 7 return 8 { 9 Lua_IsYounger = Lua_IsYounger, 10 }
在C#中調用lua代碼:
1 ILuaState lua = LuaAPI.NewState(); 2 lua.L_OpenLibs(); 3 4 PeopleLuaWrapper.RegisterCSharpMethod(lua); 5 6 People pa = new People(12); 7 People pb = new People(123); 8 9 var status = lua.L_DoFile("People.lua"); 10 11 lua.GetField(-1, "Lua_IsYounger"); 12 lua.PushLightUserData(pa); 13 lua.PushLightUserData(pb); 14 lua.Call(2, 1); 15 16 bool is_younger = lua.ToBoolean(-1);
示例代碼毫無實用意義,但應該足以說明如何實現C#與Lua之間的互相調用。
本人純粹Lua新手,這種做法也不知是否合理,或者有更簡便的實現方法,請指教。