• 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,重载时会无法区分。

  • 相关阅读:
    elasticsearch:shard 和 replica 机制
    zookeeper 的 docker 镜像使用
    zookeeper 图形化的客户端工具:ZooInspector
    zookeeper 学习资料
    Spring Cloud 与 Dubbo、Spring Cloud 与 Docker、Spring Cloud 与 Kubernetes 比较
    可视化界面:ElasticSearch Head,最方便的是直接下载谷歌浏览器扩展程序
    java 中 heap(堆)和stack(栈)的区别
    Elasticsearch 学习资料
    025_lua脚本语言
    004_zookeeper运维之maxClientCnxns overflow
  • 原文地址:https://www.cnblogs.com/coderJiebao/p/unity3d22.html
Copyright © 2020-2023  润新知