- 目錄 (點擊無法跳轉的那種 ^_^ )
- 開始
- 加載Lua文件
- 在C#腳本中,獲取Lua中的變量
- 在C#腳本中,獲取Lua中的表
- 在C#腳本中,獲取Lua中的函數
- 官方使用建議
- 自定義Loader加載指定目錄的Lua腳本
- 待補充....
- 開始
引入命名空間:
using XLua;
創建Lua的運行環境:
LuaEnv luaenv = new LuaEnv();
這里有一段官方提示:
一個LuaEnv實例對應Lua虛擬機,出於開銷的考慮,建議全局唯一。
釋放Lua:
luaenv.Dispose();
- 加載Lua文件
注意,當你使用以下方法讀取lua文件的時候
luaenv.DoString("require '文件名'");
這個文件名可以不用添加.lua或者.txt的后綴名,但是!這個文件的后綴名真正其實是.txt! 用.lua作為后綴名,Unity不會識別。
哪能不能不用txt作為后綴呢?
這里貼上一段xLua之FAQ中的一部分:
lua源碼只能以txt后綴?
什么后綴都可以。
如果你想以TextAsset打包到安裝包(比如放到Resources目錄),Unity不認lua后綴,這是Unity的規則。
如果你不打包到安裝包,就沒有后綴的限制:比如自行下載到某個目錄(這也是熱更的正確姿勢),然后通過CustomLoader或者設置package.path去讀這個目錄。
那為啥xLua本身帶的lua源碼(包括示例)為什么都是txt結尾呢?因為xLua本身就一個庫,不含下載功能,也不方便運行時去某個地方下載代碼,通過TextAsset是較簡單的方式。
- 在C#腳本中,獲取Lua中的變量
首先,官方給的例子是這個樣子的:
luaenv.Global.Get<int>("a") luaenv.Global.Get<string>("b") luaenv.Global.Get<bool>("c")
以上代碼分別獲取了Lua腳本中:
number類型的a string類型的b bool類型的c
這里需要注意的一點是:在獲取number類型時,一定要注意接收的類型
當Lua中的number類型是小數時,使用Get<int>來獲取會獲取不到該值;返回值為0。
但是使用Get<double>(或者float)來獲取number類型時,無論是整數還是小數,都可以獲取到。
- 在C#腳本中,獲取Lua中的表
第一種方法,不推薦,官方描述:
映射到普通class或struct:
要注意的是,這個過程是值拷貝,如果class比較復雜代價會比較大。而且修改class的字段值不會同步到table,反過來也不會。
方法如下:
1 -- 這是lua中的表 2 table = { 3 name = "xm",age = 12 4 }
需要在C#中定義一個與lua表中的元素名稱,類型一樣,而且必須是public的 (數量可以不一致)的class或者struct;
//這是在C#中定義的類 class MyClass { public string name; public int age; }
准備完畢后調用:
1 MyClass mc = e.Global.Get<MyClass>("table"); 2 print(mc.name); 3 print(mc.age); 4 //輸出: 5 //xm 6 //12
使用這種方法時,只能獲取到你在C#類中定義的同名變量,若是你在表中定義了第三個變量,不去獲取;又或是你在C#類中使用了不一樣的名稱變量,去獲取,都不會得到這個值(不一樣名稱會為null),同時也不會報錯。
第二種方法,官方描述:
映射到一個interface:
這種方式依賴於生成代碼(如果沒生成代碼會拋InvalidCastException異常),代碼生成器會生成這個interface的實例,如果get一個屬性,生成代碼會get對應的table字段,如果set屬性也會設置對應的字段。甚至可以通過interface的方法訪問lua的函數。
定義一個接口,需與lua表中的元素名稱,類型一樣 (數量可以不一致)
注意!這個接口必須是public的,且需要在上面加上[CSharpCallLua] ,並且要在Unity中重新生成xLua代碼 這里有坑,未來補上
接口:
1 [CSharpCallLua] 2 public interface Itest 3 { 4 string name { get; set; } 5 int age { get; set; } 6 }
調用方法還是和class的差不多:
1 Itest test = luaenv.Global.Get<Itest>("table"); 2 Debug.Log(test.name); 3 Debug.Log(test.age);
第二種方法是引用傳遞,在C#中修改值,Lua中也會被修改。
- 在C#腳本中,獲取Lua中的函數
官方解釋:
這種是建議的方式,性能好很多,而且類型安全。缺點是要生成代碼(如果沒生成代碼會拋InvalidCastException異常)。
可以使用委托的方式:
1 [CSharpCallLua] 2 public delegate void testDelegate(int a,int b,int c,int d);
委托同樣也需要添加[CSharpCallLua],且需要為public,最后需要在Unity中重新生成xLua才可以使用。這兩項缺少一項,都會導致代碼報錯。
調用方法:
1 testDelegate ad = luaenv.Global.Get<testDelegate>("add"); 2 ad(1, 2, 3, 4);
Lua方面:
1 function add(a,b,c,d) 2 print(a+b+c+d) 3 end
如果有多個返回值,在定義委托的時候,加上out或者ref關鍵字可達到類似效果:
1 [CSharpCallLua] 2 public delegate void testDelegate(int a,out int o,ref int r);
注意:如果直接 luaenv.Dispose() 的話,會報錯:


原因是C#中有變量正在引用着Lua中的東西,需要把C#中的那個變量置空才行。
1 ad = null;
這樣操作后,Dispose就不會報錯了。
還有一種直接映射到LuaFunction但是性能消耗比上一個要大,用法 及 官方解釋:
1 LuaFunction f = luaenv.Global.Get<LuaFunction>("add"); 2 f.Call(1, 2, 3, 4);
這種方式的優缺點剛好和第一種相反。(第一種是 “性能好很多,而且類型安全”)
使用也簡單,LuaFunction上有個變參的Call函數,可以傳任意類型,任意個數的參數,返回值是object的數組,對應於lua的多返回值。
- 官方使用建議
結合以上的多種實現方法,官方給出的使用建議:
1、訪問lua全局數據,特別是table以及function,代價比較大,建議盡量少做,比如在初始化時把要調用的lua function獲取一次(映射到delegate)后,保存下來,后續直接調用該delegate即可。table也類似。
2、如果lua測的實現的部分都以delegate和interface的方式提供,使用方可以完全和xLua解耦:由一個專門的模塊負責xlua的初始化以及delegate、interface的映射,然后把這些delegate和interface設置到要用到它們的地方。
- 自定義Loader加載指定目錄的Lua腳本
設置自定義Loader:
LuaEnv env = new LuaEnv(); env.AddLoader(MyLoader);
AddLoader這個函數的參數是一個 返回值為byte類型數組,參數是ref string類型 的委托,為方便理解,下面貼出詳細代碼;
紅色字體的MyLoader的定義如下:
1 public byte[] MyLoader (ref string filePath) 2 { 3 //方法體 4 return System.Text.Encoding.UTF8.GetBytes("這里是lua文件的路徑位置"); 5 }
待補充...
