Unity XLua 官方教程學習


一、Lua 文件加載

1. 執行字符串

 1 using UnityEngine;
 2 using XLua;
 3 
 4 public class ByString : MonoBehaviour {
 5     LuaEnv luaenv = null;
 6     // Use this for initialization
 7     void Start () {
 8         luaenv = new LuaEnv();
 9         // 執行代碼塊,輸出 hello world
10         luaenv.DoString("print('hello world')");
11     }
12     
13     // Update is called once per frame
14     void Update () {
15         if (luaenv != null)
16         {
17             // 清楚 Lua 未手動釋放的 LuaBase 對象
18             luaenv.Tick();
19         }
20     }
21 
22     void OnDestroy()
23     {
24         // 銷毀
25         luaenv.Dispose();
26     }
27 }

  其中 Dostring 函數返回值即為代碼塊里 return 語句的返回值。

 

2. 加載 Lua 文件

1 luaenv = new LuaEnv();
2 // 加載 byfile Lua 文件
3 luaenv.DoString("require 'byfile'");

  其中 Lua 文件代碼為:

print('hello world')

  需要注意的是因為 Resource 只支持有限的后綴,放 Resources 下 lua 文件得加上 txt 后綴,如:byfile.lua.txt。

 

3. 自定義 Loader

 1 void Start()
 2 {
 3     luaenv = new LuaEnv();
 4     // 自定義 loader
 5     luaenv.AddLoader((ref string filename) => {
 6         // 若要加載 InMemory
 7             if (filename == "InMemory")
 8             {
 9                 string script = "return {ccc = 9999}";
10                 // 將字符串轉換成byte[]
11                 return System.Text.Encoding.UTF8.GetBytes(script);
12             }
13             return null;
14         });
15     // 執行代碼塊,訪問table中的常量ccc
16     luaenv.DoString("print('InMemory.ccc=', require('InMemory').ccc)");
17 }

  通過 Addloader 可以注冊個回調,該回調參數是字符串,返回一個 byte 數組。lua 代碼里調用 require 時,參數就會傳給回調。

  注意,require 返回一個由模塊常量和函數組成的table。

 

二、C# 訪問 Lua

  其中 lua 代碼如下:

 1 a = 1
 2 b = 'hello world'
 3 c = true
 4 
 5 d = {
 6     f1 = 12, f2 = 34, 
 7     1, 2, 3,
 8     add = function(self, a, b) 
 9         print('d.add called')
10         return a + b 
11     end
12 }
13 
14 function e()
15     print('i am e')
16 end
17 
18 function f(a, b)
19     print('a', a, 'b', b)
20     return 1, {f1 = 1024}
21 end
22         
23 function ret_e()
24     print('ret_e called')
25     return e
26 end

  其中包含常量,表和函數。C# 代碼如下:

 1 public class DClass
 2 {
 3     public int f1;          // 屬性與Xlua里的對應
 4     public int f2;
 5 }
 6     
 7 [CSharpCallLua]
 8 public interface ItfD
 9 {
10     int f1 { get; set; }
11     int f2 { get; set; }
12     int add(int a, int b);
13 }
14 
15 // 生成代碼
16 // 若有多個參數,可用 out 屬性接收剩下的返回
17 [CSharpCallLua]
18 public delegate int FDelegate(int a, string b, out DClass c);
19 
20 [CSharpCallLua]
21 public delegate Action GetE();
22 
23 // Use this for initialization
24 void Start()
25 {
26     luaenv = new LuaEnv();
27     luaenv.DoString(script);
28 
29     // 訪問全局常量
30     Debug.Log("_G.a = " + luaenv.Global.Get<int>("a"));         // 1
31     Debug.Log("_G.b = " + luaenv.Global.Get<string>("b"));      // hello world
32     Debug.Log("_G.c = " + luaenv.Global.Get<bool>("c"));        // Ture
33 
34     // 訪問全局的 table
35     // 映射到普通的class或struct
36     //映射到有對應字段的class,值拷貝,class字段的修改不會影響到table,反之也不會
37     DClass d = luaenv.Global.Get<DClass>("d");
38     Debug.Log("_G.d = {f1=" + d.f1 + ", f2=" + d.f2 + "}");     // 12 34
39 
40     // 映射有 key 的 
41     Dictionary<string, double> d1 = luaenv.Global.Get<Dictionary<string, double>>("d");//映射到Dictionary<string, double>,值拷貝
42     Debug.Log("_G.d = {f1=" + d1["f1"] + ", f2=" + d1["f2"] + "}, d.Count=" + d1.Count);    // 12 34 2
43 
44     // 映射沒有 key 的
45     List<double> d2 = luaenv.Global.Get<List<double>>("d"); //映射到List<double>,值拷貝
46     Debug.Log("_G.d.len = " + d2.Count);                // 3
47 
48     // 映射到一個 interface
49     // 要在 interface 定義前加 [CSharpCallLua]
50     ItfD d3 = luaenv.Global.Get<ItfD>("d"); //映射到interface實例,by ref,這個要求interface加到生成列表,否則會返回null,建議用法
51     d3.f2 = 1000;               // 外部修改會影響 Lua 內的值
52     Debug.Log("_G.d = {f1=" + d3.f1 + ", f2=" + d3.f2 + "}");       // 12 1000
53     Debug.Log("_G.d:add(1, 2)=" + d3.add(1, 2));                    // d.add called
54 
55     //映射到LuaTable,by ref
56     LuaTable d4 = luaenv.Global.Get<LuaTable>("d");
57     Debug.Log("_G.d = {f1=" + d4.Get<int>("f1") + ", f2=" + d4.Get<int>("f2") + "}");
58 
59     // 訪問一個全局的函數
60     // 映射到 delegate
61     Action e = luaenv.Global.Get<Action>("e");//映射到一個delgate,要求delegate加到生成列表,否則返回null,建議用法
62     e();                        // i am e
63 
64     FDelegate f = luaenv.Global.Get<FDelegate>("f");
65     DClass d_ret;
66     // 多值返回,可用out接收多余的參數
67     // 輸出 a 100 b John
68     int f_ret = f(100, "John", out d_ret);//lua的多返回值映射:從左往右映射到c#的輸出參數,輸出參數包括返回值,out參數,ref參數
69     // table只含有常量f1,所以f2賦值為0
70     Debug.Log("ret.d = {f1=" + d_ret.f1 + ", f2=" + d_ret.f2 + "}, ret=" + f_ret);      // 1024 0 1
71 
72     GetE ret_e = luaenv.Global.Get<GetE>("ret_e");//delegate可以返回更復雜的類型,甚至是另外一個delegate
73     e = ret_e();
74     e();
75 
76     // 映射到 LuaFunction
77     LuaFunction d_e = luaenv.Global.Get<LuaFunction>("e");
78     // Call 函數可以傳任意類型,任意個數的參數
79     d_e.Call();
80 
81 }

  訪問 lua 全局數據,特別是 table 以及 function,代價比較大,建議盡量少做,比如在初始化時調用獲取一次后,保存下來,后續直接使用即可。

 

三、Lua 調用 C#

  其中 C# 代碼如下:

  1 namespace Tutorial
  2 {
  3     [LuaCallCSharp]
  4     public class BaseClass
  5     {
  6         public static void BSFunc()
  7         {
  8             Debug.Log("Driven Static Func, BSF = "+ BSF);
  9         }
 10 
 11         public static int BSF = 1;
 12 
 13         public void BMFunc()
 14         {
 15             Debug.Log("Driven Member Func, BMF = " + BMF);
 16         }
 17 
 18         public int BMF { get; set; }
 19     }
 20 
 21     public struct Param1
 22     {
 23         public int x;
 24         public string y;
 25     }
 26 
 27     [LuaCallCSharp]
 28     public enum TestEnum
 29     {
 30         E1,
 31         E2
 32     }
 33 
 34     [LuaCallCSharp]
 35     public class DrivenClass : BaseClass
 36     {
 37         [LuaCallCSharp]
 38         public enum TestEnumInner
 39         {
 40             E3,
 41             E4
 42         }
 43 
 44         public void DMFunc()
 45         {
 46             Debug.Log("Driven Member Func, DMF = " + DMF);
 47         }
 48 
 49         public int DMF { get; set; }
 50 
 51         public double ComplexFunc(Param1 p1, ref int p2, out string p3, Action luafunc, out Action csfunc)
 52         {
 53             Debug.Log("P1 = {x=" + p1.x + ",y=" + p1.y + "},p2 = "+ p2);
 54             luafunc();
 55             p2 = p2 * p1.x;
 56             p3 = "hello " + p1.y;
 57             csfunc = () =>
 58             {
 59                 Debug.Log("csharp callback invoked!");
 60             };
 61             return 1.23;
 62         }
 63 
 64         public void TestFunc(int i)
 65         {
 66             Debug.Log("TestFunc(int i)");
 67         }
 68 
 69         public void TestFunc(string i)
 70         {
 71             Debug.Log("TestFunc(string i)");
 72         }
 73 
 74         public static DrivenClass operator +(DrivenClass a, DrivenClass b)
 75         {
 76             DrivenClass ret = new DrivenClass();
 77             ret.DMF = a.DMF + b.DMF;
 78             return ret;
 79         }
 80 
 81         public void DefaultValueFunc(int a = 100, string b = "cccc", string c = null)
 82         {
 83             UnityEngine.Debug.Log("DefaultValueFunc: a=" + a + ",b=" + b + ",c=" + c);
 84         }
 85 
 86         public void VariableParamsFunc(int a, params string[] strs)
 87         {
 88             UnityEngine.Debug.Log("VariableParamsFunc: a =" + a);
 89             foreach (var str in strs)
 90             {
 91                 UnityEngine.Debug.Log("str:" + str);
 92             }
 93         }
 94 
 95         public TestEnum EnumTestFunc(TestEnum e)
 96         {
 97             Debug.Log("EnumTestFunc: e=" + e);
 98             return TestEnum.E2;
 99         }
100 
101         public Action<string> TestDelegate = (param) =>
102         {
103             Debug.Log("TestDelegate in c#:" + param);
104         };
105 
106         public event Action TestEvent;
107 
108         public void CallEvent()
109         {
110             TestEvent();
111         }
112 
113         public ulong TestLong(long n)
114         {
115             return (ulong)(n + 1);
116         }
117 
118         class InnerCalc : ICalc
119         {
120             public int add(int a, int b)
121             {
122                 return a + b;
123             }
124 
125             public int id = 100;
126         }
127 
128         public ICalc GetCalc()
129         {
130             return new InnerCalc();
131         }
132 
133         public void GenericMethod<T>()
134         {
135             Debug.Log("GenericMethod<" + typeof(T) + ">");
136         }
137     }
138 
139     [LuaCallCSharp]
140     public interface ICalc
141     {
142         int add(int a, int b);
143     }
144 
145     [LuaCallCSharp]
146     public static class DrivenClassExtensions
147     {
148         public static int GetSomeData(this DrivenClass obj)
149         {
150             Debug.Log("GetSomeData ret = " + obj.DMF);
151             return obj.DMF;
152         }
153 
154         public static int GetSomeBaseData(this BaseClass obj)
155         {
156             Debug.Log("GetSomeBaseData ret = " + obj.BMF);
157             return obj.BMF;
158         }
159 
160         public static void GenericMethodOfString(this DrivenClass obj)
161         {
162             obj.GenericMethod<string>();
163         }
164     }
165 }

 

  其中可變參數可用  params string[] strs 實現。要在 Lua 直接訪問什么,記得在定義前加上  [LuaCallCSharp] 

  對應的 lua 代碼為:

  1 function demo()
  2     -- new C#對象
  3     -- 沒有new,所有C#相關的都放在CS下
  4     local newGameObj = CS.UnityEngine.GameObject()
  5     -- 創建一個名為helloworld的物體
  6     local newGameObj2 = CS.UnityEngine.GameObject('helloworld')
  7     print(newGameObj, newGameObj2)
  8 
  9     --訪問靜態屬性,方法
 10     local GameObject = CS.UnityEngine.GameObject
 11     print('UnityEngine.Time.deltaTime:', CS.UnityEngine.Time.deltaTime) --讀靜態屬性
 12     CS.UnityEngine.Time.timeScale = 0.5 --寫靜態屬性
 13     -- 查找物體 helloworld
 14     print('helloworld', GameObject.Find('helloworld')) --靜態方法調用
 15 
 16     --訪問成員屬性,方法
 17     local DrivenClass = CS.Tutorial.DrivenClass
 18     local testobj = DrivenClass()
 19     testobj.DMF = 1024--設置成員屬性
 20     print(testobj.DMF)--讀取成員屬性
 21     -- 輸出 DMF=1024
 22     testobj:DMFunc()--成員方法 使用冒號
 23 
 24     --基類屬性,方法
 25     print(DrivenClass.BSF)--讀基類靜態屬性 1
 26     DrivenClass.BSF = 2048--寫基類靜態屬性
 27     DrivenClass.BSFunc();--基類靜態方法 2048
 28     -- BMF 初始為0
 29     print(testobj.BMF)--讀基類成員屬性 0
 30     testobj.BMF = 4096--寫基類成員屬性
 31     testobj:BMFunc()--基類方法調用 4096
 32 
 33     --復雜方法調用
 34     -- 參數處理規則:C#的普通參數和ref修飾的算一個參數,out不算,從左往右順序
 35     -- 返回值處理規則:返回值(如果有)算第一個,out,ref修飾的參數算一個,從左往右
 36     local ret, p2, p3, csfunc = testobj:ComplexFunc({x=3, y = 'john'}, 100, function()
 37        print('i am lua callback')
 38     end)
 39     print('ComplexFunc ret:', ret, p2, p3, csfunc)
 40     csfunc()
 41 
 42    --重載方法調用
 43    testobj:TestFunc(100)
 44    testobj:TestFunc('hello')
 45 
 46    --操作符
 47    local testobj2 = DrivenClass()
 48    testobj2.DMF = 2048
 49    -- 輸出DMF=1024+2048=3072
 50    print('(testobj + testobj2).DMF = ', (testobj + testobj2).DMF)
 51 
 52    --默認值
 53    testobj:DefaultValueFunc(1)
 54    testobj:DefaultValueFunc(3, 'hello', 'john')
 55 
 56    --可變參數
 57    testobj:VariableParamsFunc(5, 'hello', 'john')
 58 
 59    --Extension methods
 60    print(testobj:GetSomeData())
 61    print(testobj:GetSomeBaseData()) --訪問基類的Extension methods
 62    testobj:GenericMethodOfString()  --通過Extension methods實現訪問泛化方法
 63 
 64    --枚舉類型
 65    -- 返回E2
 66    local e = testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)
 67    -- 輸出枚舉類型格式為 E2:1
 68    print(e, e == CS.Tutorial.TestEnum.E2)
 69    -- 整數或者字符串到枚舉類型的轉換
 70    print(CS.Tutorial.TestEnum.__CastFrom(1), CS.Tutorial.TestEnum.__CastFrom('E1'))
 71    print(CS.Tutorial.DrivenClass.TestEnumInner.E3)
 72    assert(CS.Tutorial.BaseClass.TestEnumInner == nil)
 73 
 74    --委托
 75    testobj.TestDelegate('hello') --直接調用
 76    local function lua_delegate(str)
 77        print('TestDelegate in lua:', str)
 78    end
 79    testobj.TestDelegate = lua_delegate + testobj.TestDelegate --combine,這里演示的是C#delegate作為右值,左值也支持
 80    testobj.TestDelegate('hello')
 81    testobj.TestDelegate = testobj.TestDelegate - lua_delegate --remove
 82    testobj.TestDelegate('hello')
 83 
 84    --事件
 85    local function lua_event_callback1() print('lua_event_callback1') end
 86    local function lua_event_callback2() print('lua_event_callback2') end
 87    -- 增加回調事件
 88    testobj:TestEvent('+', lua_event_callback1)
 89    testobj:CallEvent()
 90    testobj:TestEvent('+', lua_event_callback2)
 91    testobj:CallEvent()
 92    -- 移除回調事件
 93    testobj:TestEvent('-', lua_event_callback1)
 94    testobj:CallEvent()
 95    testobj:TestEvent('-', lua_event_callback2)
 96 
 97    --64位支持
 98    local l = testobj:TestLong(11)
 99    print(type(l), l, l + 100, 10000 + l)
100 
101    --typeof
102    -- 增加粒子系統
103    newGameObj:AddComponent(typeof(CS.UnityEngine.ParticleSystem))
104 
105    --cast 強轉
106    -- 返回 InnerCalc 類
107    local calc = testobj:GetCalc()
108    print('assess instance of InnerCalc via reflection', calc:add(1, 2))
109    assert(calc.id == 100)
110    -- 強轉
111    cast(calc, typeof(CS.Tutorial.ICalc))
112    print('cast to interface ICalc', calc:add(1, 2))
113    assert(calc.id == nil)
114 end
115 
116 demo()
117 
118 --協程下使用
119 local co = coroutine.create(function()
120    print('------------------------------------------------------')
121    demo()
122 end)
123 assert(coroutine.resume(co))

  其中 assert 函數用於有錯誤時拋出異常。

  注意,C# 的 int, float, double 都對應於 lua 的 number,重載時會無法區分。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM