本文內容轉載自:http://www.javashuo.com/article/p-zzmhghys-ds.html 。很是感謝原做者慷慨地受權轉載,比心!@blueberryzzz 是位大神,歡迎你們關注他的博客。馬三對原文的排版與結構作了微調,以便更合適閱讀。html
每一個wrap文件都是對一個c#類的包裝,在lua中,經過對wrap類中的函數調用,間接的對c#實例進行操做。c#
這部分主要經過分析類的反射信息完成。微信
使用UnityEngine_GameObjectWrap.cs進行舉例。函數
1 public static void Register(LuaState L) 2 { 3 L.BeginClass(typeof(UnityEngine.GameObject), typeof(UnityEngine.Object)); 4 L.RegFunction("CreatePrimitive", CreatePrimitive); 5 L.RegFunction("GetComponent", GetComponent); 6 L.RegFunction("GetComponentInChildren", GetComponentInChildren); 7 L.RegFunction("GetComponentInParent", GetComponentInParent); 8 L.RegFunction("GetComponents", GetComponents); 9 L.RegFunction("GetComponentsInChildren", GetComponentsInChildren); 10 L.RegFunction("GetComponentsInParent", GetComponentsInParent); 11 L.RegFunction("SetActive", SetActive); 12 L.RegFunction("CompareTag", CompareTag); 13 L.RegFunction("FindGameObjectWithTag", FindGameObjectWithTag); 14 L.RegFunction("FindWithTag", FindWithTag); 15 L.RegFunction("FindGameObjectsWithTag", FindGameObjectsWithTag); 16 L.RegFunction("Find", Find); 17 L.RegFunction("AddComponent", AddComponent); 18 L.RegFunction("BroadcastMessage", BroadcastMessage); 19 L.RegFunction("SendMessageUpwards", SendMessageUpwards); 20 L.RegFunction("SendMessage", SendMessage); 21 L.RegFunction("New", _CreateUnityEngine_GameObject); 22 L.RegFunction("__eq", op_Equality); 23 L.RegFunction("__tostring", ToLua.op_ToString); 24 L.RegVar("transform", get_transform, null); 25 L.RegVar("layer", get_layer, set_layer); 26 L.RegVar("activeSelf", get_activeSelf, null); 27 L.RegVar("activeInHierarchy", get_activeInHierarchy, null); 28 L.RegVar("isStatic", get_isStatic, set_isStatic); 29 L.RegVar("tag", get_tag, set_tag); 30 L.RegVar("scene", get_scene, null); 31 L.RegVar("gameObject", get_gameObject, null); 32 L.EndClass(); 33 }
這部分代碼由GenRegisterFunction()生成,能夠看到,這些代碼分爲了4部分:this
BeginClass部分lua
①用於建立類和類的元表,若是類的元表的元表(類的元表是承載每一個類方法和屬性的實體,類的元表的元表就是類的父類)
②將類添加到loaded表中。
③設置每一個類的元表的通用的元方法和屬性,__gc,name,ref,__cal,__index,__newindex。spa
RegFunction部分pwa
每個RefFunction作的事都很簡單,將每一個函數轉化爲一個指針,而後添加到類的元表中去,與將一個c函數註冊到lua中是同樣的。指針
RegVar部分code
每個變量或屬性或被包裝成get_xxx,set_xxx函數註冊添加到類的元表的gettag,settag表中去,用於調用和獲取。
EndClass部分
作了兩件事:
①設置類的元表
②把該類加到所在模塊表明的表中(如將GameObject加入到UnityEngine表中)
因爲構造函數,this[],get_xxx,set_xxx的原理都差很少,都是經過反射的信息生成的,因此放在一塊兒用一個實例講一下(使用GameObject的GetComponent函數進行說明)。
1 [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] 2 static int GetComponent(IntPtr L) 3 { 4 try 5 { 6 //獲取棧中參數的個數 7 int count = LuaDLL.lua_gettop(L); 8 //根據棧中元素的個數和元素的類型判斷該使用那一個重載 9 if (count == 2 && TypeChecker.CheckTypes<string>(L, 2)) 10 { 11 //將棧底的元素取出來,這個obj在棧中是一個fulluserdata,須要先將這個fulluserdata轉化成對應的c#實例,也就是調用這個GetComponent函數的GameObject實例 12 UnityEngine.GameObject obj = (UnityEngine.GameObject)ToLua.CheckObject(L, 1, typeof(UnityEngine.GameObject)); 13 //將棧底的上一個元素取出來,也就是GetComponent(string type)的參數 14 string arg0 = ToLua.ToString(L, 2); 15 //經過obj,arg0直接第調用GetCompent(string type)函數 16 UnityEngine.Component o = obj.GetComponent(arg0); 17 //將調用結果壓棧 18 ToLua.Push(L, o); 19 //返回參數的個數 20 return 1; 21 } 22 //另外一個GetComponent的重載,跟上一個差很少,就不詳細說明了 23 else if (count == 2 && TypeChecker.CheckTypes<System.Type>(L, 2)) 24 { 25 UnityEngine.GameObject obj = (UnityEngine.GameObject)ToLua.CheckObject(L, 1, typeof(UnityEngine.GameObject)); 26 System.Type arg0 = (System.Type)ToLua.ToObject(L, 2); 27 UnityEngine.Component o = obj.GetComponent(arg0); 28 ToLua.Push(L, o); 29 return 1; 30 } 31 //參數數量或類型不對,沒有找到對應的重載,拋出錯誤 32 else 33 { 34 return LuaDLL.luaL_throw(L, "invalid arguments to method: UnityEngine.GameObject.GetComponent"); 35 } 36 } 37 catch (Exception e) 38 { 39 return LuaDLL.toluaL_exception(L, e); 40 } 41 }
能夠看到,GetComponent函數的內容,其實就是經過反射分析GetComponent的重載個數,每一個重載的參數個數,類型生成的。具體內容和lua調用c函數差很少。
假如說在lua中有這麼一個調用:
1 local tempGameObject = UnityEngine.GameObject("temp") 2 local transform = tempGameObject.GetComponent("Transform")
第二行代碼對應的實際調用過程是:
其中3-7的操做都在c#中進行,也就是wrap文件中的GetComponent函數。
使用GameObjectWrap進行舉例。
能夠看到GameObject的全部功能都是經過一個元表實現的,經過這個元表能夠調用GameObjectWrap文件中的各個函數來實現對GameObject實例的操做,這個元表對使用者來講是不可見的,由於咱們平時只會在代碼中調用GameObject類,GameObject實例,並不會直接引用到這個元表,接下來來分析一下GameObject類,GameObject實例與這個元表的關係:
local tempGameObject = UnityEngine.GameObject("temp") local instanceID = tempGameObject.GetInstanceID()
在瞭解了GameObject元表後,這些只是一些基礎的元表操做,就很少作解釋。
前面說了每個c#實例在lua中是一個內容爲整數索引的fulluserdata,在進行函數調用時,經過這個整數索引查找和調用這個索引表明的實例的函數和變量。生成或使用一個表明c#實例的lua變量的過程大概是這樣的。還用這個例子來講明:
local tempGameObject = UnityEngine.GameObject("temp") local transform = tempGameObject.GetComponent("Transform")
因此說lua中調用和建立的c#實例實際都是存在c#中的objects表中,lua中的變量只是一個持有該c#實例索引位置的fulluserdata,並無直接對c#實例進行引用。
對c#實例進行函數的調用和變量的修改都是經過元表調用操做wrap文件中的函數進行的。以上就是c#類如何經過wrap類在lua中進行使用的原理。
若是以爲本篇博客對您有幫助,能夠掃碼小小地鼓勵下馬三,馬三會寫出更多的好文章,支持微信和支付寶喲!
做者:馬三小夥兒
出處:http://www.javashuo.com/article/p-giqkhhka-s.html 請尊重別人的勞動成果,讓分享成爲一種美德,歡迎轉載。另外,文章在表述和代碼方面若有不妥之處,歡迎批評指正。留下你的腳印,歡迎評論!