轉載請標明出處:http://www.cnblogs.com/zblade/c++
在實際的項目中,大部分業務邏輯 程序員只須要負責lua層編寫邏輯便可,或者在c#層添加一些靜態函數,供lua層調用。那麼對於具體的相互之間的交互,又是如何進行的?本文就寫一寫我的的一些探究筆記吧。本文會寫不少代碼,我就用截圖來展現吧,編輯寫代碼不大方便,有點蛋疼~程序員
1、c#函數的導出c#
我就從外部接口開始理一遍總體思路吧,想了一下,仍是從代碼思路來解釋比較容易。函數
首先咱們的工程中都會有一個slua的導出接口:lua
這樣的一個接口,是用來將UnityEngine中的類導出的實現API,其總體的思路是:spa
1)首先加載UnityEngine這個程序集:3d
Assembly assembly = Assembly.Load("UnityEngine")
2)而後獲取資中的可導出類型:code
Type[] types = assembly.GetExportedTypes();
3) 作一次過濾,主要是對於某些須要導出的類和不須要導出的類作一次過濾剔除和添加,這個不一樣項目不同,不作展現;blog
4)將這些過濾後的類型,逐個作一次導出,好比相機類,能夠導出爲:接口
5)將這些導出的類Lua_xxx合併在一塊兒做爲一個Bind, 提供一個靜態獲取方法GetBindList()
這是第一步,完成對c#和unity中的方法導出,將每一個不一樣程序集中的類中的方法和屬性都暴露出來,作一個導出。
2、導出的c#文件的註冊到Lua虛擬機中
這部分須要結合遊戲的啓動來理解,在遊戲的啓動時刻,咱們都會啓動一個Lua的虛擬機,好比這樣:
在啓動虛擬機後,須要執行虛擬機的Init操做:
m_LuaSvr.init(xxxx)
在這個函數中,執行Bind的操做:doBind
其中的關鍵操做爲collectBindInfo, 這個函數分爲2部分:
1)獲取當前程序集,以及程序集中設置爲LuaBinderAttribute的類型:
2)根據獲取的類型,逐個反射執行第一部分最後的GetBindList函數:
這樣經過c#的反射,就能夠動態的獲取前面導出的全部LuaXXX類文件了,回到Bind操做,對於這些獲取的Lua_XXX文件,執行Lua虛擬機的註冊操做:
action(L)
也就是導出文件中的reg操做:
看看其操做,首先是newtable的操做:
建立2個table,分別用來作static和instance的填充,而後填充的操做addMember:
對於不一樣的參數,會重載不一樣的addMember操做,這兒就舉例一個,pushValue就是將func註冊到該table中:
LuaDll.lua_pushcclosure(L, function, 0)
就是將該函數填充到lua表中,能夠經過key名的查找來獲取該函數,從而執行相關的調用。
最後會在該reg操做中爲該類建立一個metatable
回到最初的,不斷的循環執行,就能夠加載整個c#相關導出類到Lua虛擬機中
總結:到如今爲止,能夠知道整個c#函數在導出過程當中的操做,在啓動時候如何經過程序集和反射來實現動態的加載,最後Lua的虛擬機中都會註冊前面導出的類文件的相關函數和屬性。
而咱們已經知道,lua文件在執行的時候,是會編譯成字節碼在lua的虛擬機中執行的,這樣lua的字節碼和c#的導出文件,都在同一個環境中執行,調用pcall就能夠相互的執行和調用了。
寫這篇文章是基於偶然翻看到老外寫的一個在unity中用c++作腳原本編寫遊戲邏輯,而且實現了c#和c++之間的相互交互調用,因此我也翻看了一下c#是如何實現的,固然寫的比較簡陋,還有不少細節須要推敲,你們能夠翻看本身的項目代碼,留言討論