Unity中 Xlua使用整理(二)

发布于:2025-02-10 ⋅ 阅读:(47) ⋅ 点赞:(0)

1.Xlua的配置应用

xLua所有的配置都支持三种方式:打标签静态列表动态列表
配置要求
列表方式均必须是static的字段/属性
列表方式均必须放到一个static类
建议不用标签方式
建议列表方式配置放Editor目录(如果是Hotfix配置,而且类位于Assembly-CSharp.dll之外的其它dll,必须放Editor目录)

1.打标签

xLua用白名单来指明生成哪些代码,而白名单通过attribute来配置,该方式方便,但在il2cpp下会增加不少的代码量,不建议使用

1.LuaCallCSharp

一个C#类型加了这个配置,xLua会生成这个类型的适配代码(包括构造该类型实例,访问其成员属性、方法,静态属性、方法)。一个类型的扩展方法(Extension Methods)加了这配置,也会生成适配代码并追加到被扩展类型的成员方法上。xLua只会生成加了该配置的类型,不会自动生成其父类的适配代码,当访问子类对象的父类方法,如果该父类加了LuaCallCSharp配置,则执行父类的适配代码。如果没有适配代码则会尝试用反射来访问,但反射访问性能不佳,在il2cpp下有可能因为代码剪裁而导致无法访问。

1.打标签

[LuaCallCSharp]
public class TestObj
{
    public void test(testStruct t)
    {
        Debug.Log($"{t.a},{t.c}");
    }
}

2.静态列表

   [LuaCallCSharp]
   public static List<Type> luaCallCsharp = new List<Type>
   {
       typeof(TestObj),
   };

  上面的类加了此标签,就会生成适配代码

 2.ReflectionUse

一个C#类型类型加了这个配置,xLua会生成link.xml阻止il2cpp的代码剪裁。对于扩展方法,必须加上 LuaCallCSharp 或者 ReflectionUse 才可以被访问到。
建议所有要在Lua访问的类型,要么加LuaCallCSharp,要么加上ReflectionUse,这才能够保证在各平台都能正常运行。

如何配置?

[ReflectionUse]
public class TestReflectionUseObj
{

}

link.xml保存着打上LuaCallCSharp和ReflectionUse标签的类

3.DoNotGen

指明一个类里头的部分函数、字段、属性不生成代码,通过反射访问。
只能标准 Dictionary<Type, List<string>> 的field或者property。key指明的是生效的类,value是一个列表,配置的是不生成代码的函数、字段、属性的名字。

如何配置?

[LuaCallCSharp]
public class TestDontGen
{
    public int a1;

    public int a2;
}

1.打标签(这种方式行不通)

在生成代码中,a2还是生成和a1一样的适配函数

2.静态列表

public static class ExportCfg
{
    [DoNotGen]
    public static Dictionary<Type,List<string>> dontGenDic = new Dictionary<Type, List<string>> {
        [typeof(TestDontGen)] = new List<string> { "a2" },
    };
}

4.CSharpCallLua

把一个lua函数适配到一个C# delegate(一类是C#侧各种回调:UI事件,delegate参数,比如List<T>:ForEach;另外一类场景是通过LuaTable的Get函数指明一个lua函数绑定到一个delegate),或者把一个lua table适配到一个C# interface时,使用该标签。

如何配置?

1.打标签:

   [CSharpCallLua]
   public interface IPlayerPosition
   {
       int x { get; set; }
       int y { get; set; }
       int z { get; set; }

       void add(int x, int y, int z);
       void sub(int x, int y, int z);
   }

   [CSharpCallLua]
   public delegate void AddMethod(LuaTable self, int x, int y, int z);

   [CSharpCallLua]
   public delegate Action addAc(LuaTable t, int x, int y, int z);

    [CSharpCallLua]
    public delegate void test1(int x);

    [CSharpCallLua]
    public delegate Action test2(int x);

2.静态列表:

[CSharpCallLua]
public static List<Type> CsharpCallLua = new List<Type> { 
   typeof(IPlayerPosition),
   typeof(AddMethod),
   typeof(addAc),
   typeof(test1),
   typeof(test2),
};

 生成代码如下:接口生成独立文件,委托事件生成在DelegateGenBridge文件中

 

5.GCOptimize

xLua无参构造函数的复杂类型(struct)的默认传递方式是引用传递,当lua侧使用完毕释放该对象的引用时,会产生一次gc。
一个C#纯值类型(注:指的是一个只包含值类型的struct,可以嵌套其它只包含值类型的struct)或者C#枚举值加上这个标签之后,XLua会生成gc优化代码,在lua和c#间传递将不产生(C#)gc alloc,该类型的数组(从xlua的NoGc的例子中看只有一维数组)访问也不产生gc。

如果没有配置该标签的值类型传递

public class Test{   
    [CSharpCallLua]
    public delegate Action testAction(TestGCOptimizeValue x);

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.AddLoader(customLoader);
        luaenv.DoString("require 'main'");
        ta = luaenv.Global.Get<testAction>("testAction");
    }

    private void Update()
    {
        if (Application.isPlaying)
        {
            ta?.Invoke(ts);
        }
    }
}

public struct TestGCOptimizeValue
{
    public int a;
    public int b;
    private float f;
    //[AdditionalProperties]
    public float F { get => f; set => f = value; }
}

生成的代码如下:

将struct类型装箱转换为object再进行处理。

如何配置?

[GCOptimize]
public struct TestGCOptimizeValue
{
    public int a;
    public int b;
    public float f;
}

 加上此标签后,就会在PackUnpack中生成适配代码

 

然后调用函数生成代码如下:

struct 满足条件如下:

1.struct允许嵌套其它struct,但它以及它嵌套的struct只能包含这几种基本类型:byte、sbyte、short、ushort、int、uint、long、ulong、float、double;例如UnityEngine定义的大多数值类型:Vector系列,Quaternion,Color。。。均满足条件,或者用户自定义的一些struct
2.该struct配置了GCOptimize属性(对于常用的UnityEngine的几个struct,Vector系列,Quaternion,Color。。。均已经配置了该属性),这个属性可以通过配置文件或者C# Attribute实现;
3.使用到该struct的地方,需要添加到生成代码列表;

6.AdditionalProperties

该标签GCOptimize的扩展配置,如果struct有的字段是私有的,需要通过属性来访问,这时就需要用到该配置(默认情况下GCOptimize只对public的field打解包)

如何配置?

如果不加此标签

[GCOptimize]
public struct TestGCOptimizeValue
{
    public int a;
    public int b;
    private float f;
    public float F { get => f; set => f = value; }
}

生成代码如下:无法生成访问f字段的代码

1.打标签方式

[GCOptimize]
public struct TestGCOptimizeValue
{
    public int a;
    public int b;
    private float f;
    [AdditionalProperties]
    public float F { get => f; set => f = value; }
}

 2.静态列表

  [AdditionalProperties]
  static Dictionary<Type, List<string>> AdditionalProperties = new Dictionary<Type, List<string>>
  {
      [typeof(TestGCOptimizeValue)] = new List<string> { "F" },
      
  };

生成代码如下:

7.BlackList

一个类型的一些成员不需要适配代码,可以通过加上该标签来实现。考虑到有可能需要把重载函数的其中一个重载列入黑名单,配置方式比较复杂,类型是 List<List<string>>,对于每个成员,在第一层List有一个条目,第二层List是个string的列表,第一个string是类型的全路径名第二个string是成员名如果成员是一个方法,还需要从第三个string开始,把其参数的类型全路径全列出来

如何配置?

[LuaCallCSharp]
public class TestBlackList
{
    public int a1;
    public int a2;

    public void Test()
    {

    }
}

若不加处理生成代码如下: 

1.打标签

C#代码:

[LuaCallCSharp]
public class TestBlackList
{
    public int a1;
    [BlackList]
    public int a2;

    [BlackList]
    public void Test()
    {

    }
}

生成代码如下: 

2.静态列表

列表中的第一个字符串是类型,第二个及以后是要屏蔽的字段

  [BlackList]
  public static List<List<string>> BlackList = new List<List<string>>()
  {
      new List<string>(){ "TestBlackList", "a2"},
      new List<string>(){ "TestBlackList", "Test"}
  };

生成代码:

注:
DoNotGen和ReflectionUse的区别是:1、ReflectionUse指明的是整个类;2、当第一次访问一个函数(字段、属性)时,ReflectionUse会把整个类都wrap,而DoNotGen只wrap该函数(字段、属性);
DoNotGen和BlackList的区别是:1、BlackList配了就不能用;2、BlackList能指明某重载函数,DoNotGen不能;

2.静态列表

有时我们无法直接给一个类型打标签,比如系统api,没源码的库,或者实例化的泛化类型,这时可以在一个静态类里声明一个静态字段,然后为这字段加上标签,并且这个字段需要放到一个静态类里,建议放到 Editor目录。

如何配置?

public static class ExportCfg
{
    [DoNotGen]
    public static Dictionary<Type, List<string>> dontGenDic = new Dictionary<Type, List<string>>
    {
        [typeof(TestDontGen)] = new List<string> { "a2" },
    };

    [BlackList]
    public static List<List<string>> BlackList = new List<List<string>>()
    {
        new List<string>(){ "TestBlackList", "a2"},
        new List<string>(){ "TestBlackList", "Test"}
    };

    [AdditionalProperties]
    public static Dictionary<Type, List<string>> AdditionalProperties = new Dictionary<Type, List<string>>
    {
        [typeof(TestGCOptimizeValue)] = new List<string> { "F" },
        
    };

    [LuaCallCSharp]
    public static List<Type> luaCallCsharp = new List<Type>
    {
        typeof(TestObj),
    };

    [CSharpCallLua]
    public static List<Type> CsharpCallLua = new List<Type> { 
       typeof(IPlayerPosition),
       typeof(AddMethod),
       typeof(addAc),
       typeof(test1),
       typeof(test2),
    };
}

3.动态列表

声明一个静态属性,打上相应的标签即可。

见HotFix。

2.HotFix

1.标识要热更新的类型

1.打标签:(不建议,在高版本 Unity 不支持)

[Hotfix]
public class TestHotFix
{
    public void TestPrint()
    {
        Debug.Log("Before Hotfix");
    }
}

2.static列表:(高版本 Unity 需要把配置文件放 Editor 目录下)

[Hotfix]
public static List<Type> by_property
{
     get
     {
        return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
              where type.Namespace == "XXXX"
              select type).ToList();
     }
}

[Hotfix]
public static List<Type> by_field = new List<Type>()
{
      typeof(HotFixSubClass),
      typeof(GenericClass<>),
};

2.API

1.xlua.hotfix(class, [method_name], fix)

class :C#类,CS.Namespace.TypeName或者字符串方式"Namespace.TypeName"表示,字符串格式和C#的Type.GetType要求一致,如果是内嵌类型(Nested Type)是非Public类型,只能用字符串方式表示"Namespace.TypeName+NestedTypeName";
method_name : 方法名,可选;
fix : 如果传了method_name,fix将会是一个function,否则通过table提供一组函数。table的组织按key是method_name,value是function的方式。

2.base(csobj)

子类override函数通过base调用父类实现。
csobj : 对象
返回值 : 新对象,可以通过该对象base上的方法

3.util.hotfix_ex(class, method_name, fix)

可以在fix函数里头执行原来的函数缺点是fix的执行会略慢。
method_name : 方法名;
fix : 用来替换C#方法的lua function

Lua侧示例:

xlua.hotfix(CS.BaseTest, 'Foo', function(self, p)
    print('BaseTest', p)
    base(self):Foo(p)
end)

3.Hotfix Flag

使用方式:

[Hotfix(HotfixFlag.xxxx)]
public class TestHotFixClass
{

}
1.Stateless、Stateful

遗留设置,Stateful 方式在新版本已经删除,使用xlua.util.state代替,默认为Stateless。
这个东西不知道是个啥玩意,从utile.state的代码和Xlua例子的代码来看,就是可以为热修复类新增一些属性事件类似的东西,在构造函数中指给Lua侧的当前类(table)一个父类(metatable)。

debug.setmetatable:

 rawget,rawset:获取或设置table的值,不从原表获取或者设置

Lua 5.4 Reference Manual

使用方式:

xlua.hotfix(CS.TestHotFixClass, {  
      ['.ctor'] = function(self)
            util.state(self, {evt = {}})
      end;
})
2.ValueTypeBoxing

值类型的适配delegate会收敛到object(这是个啥?),好处是代码量更少,不好的是值类型会产生装箱,适用于对字段敏感的业务。

就是在生成delegate的时候,

如果是HotFix标签中包含ValueTypeBoxing,就会将方法和参数的类型转换为object类型

3.IgnoreProperty

不对属性注入及生成适配代码。

4.IgnoreNotPublic

不对非public的方法注入及生成适配代码。

5.Inline

不生成适配 delegate,直接在函数体注入处理代码。

6.IntKey

不生成静态字段,而是把所有注入点放到一个数组集中管理。
好处:对字段影响小。
坏处:使用不像默认方式那么方便,需要通过id来指明hotfix哪个函数,而这个id是代码注入工具时分配的,函数到id的映射会保存在 Gen/Resources/hotfix_id_map.lua.txt,并且自动加时间戳备份到 hotfix_id_map.lua.txt 同级目录,发布手机版本后请妥善保存该文件。

C#代码:

[Hotfix(HotfixFlag.IntKey)]
public class TestHotFixInkey
{
    public int A;
    public bool B; 
    public string C;

    public int this[string field]
    {
        get { return 1; }
        set { }
    }

    public void EventCall()
    {
        Debug.Log("EventCall");
    }

    public void EventCall(int a)
    {
        Debug.Log("EventCall a");
    }

    public void test()
    {
        Debug.Log("cccccccccc");
    }
}

生成的如下:重载函数,将会一个函数名对应多个 id

要替换掉test函数

local a = function(self)
       print("Lua EventCall2")
end

CS.XLua.HotfixDelegateBridge.Set(4, a)

local tik = CS.TestHotFixInkey()
tik:test()

结果:

xlua.util 提供了 auto_id_map 函数,执行一次后你就可以像以前那样直接用类,方法名去指明修补的函数。

local a = function(self)
       print("Lua EventCall2")
end

util.auto_id_map()
xlua.hotfix(CS.TestHotFixInkey, 'test', a)

local tik = CS.TestHotFixInkey()
tik:test()

结果:

 

注意:

auto_id_map函数会require hot_id_map

一定要确保生成的hot_id_map能被加载到,如果你的自定义loader加载的文件后缀是.txt,就要确保hot_id_map.lua.txt能被加载到,如果是.lua则要确保hot_id_map.lua能被加载到。否则就会报下面的错误:

4.打补丁

Xlua可以用lua函数替换 C# 的构造函数,函数,属性,事件。

1.函数

method_name 传函数名,支持重载,不同重载都是转发到同一个 lua 函数。

Unity中 Xlua使用整理(一)_为xlua配置搜索路径-CSDN博客中的HotFix章节

2.构造函数

构造函数对应的 method_name 是 ".ctor"。和普通函数不一样的是,构造函数的热补丁是执行原有逻辑后调用lua。

C#侧代码:

[Hotfix]
[LuaCallCSharp]
public class TestHotFixClass
{
    public TestHotFixClass(){
        Debug.Log("c# .ctor");
    }

    public TestHotFixClass(int p, int c)
    {
        Debug.Log($"C# .ctor {p} , {c}");
    }
}

调用代码:

//调用代码:
luaenv.DoString("require 'main'");
TestHotFixClass testHotFixClass = new TestHotFixClass();
TestHotFixClass testHotFixClass1 = new TestHotFixClass(10, 20);

Lua侧代码:

xlua.hotfix(CS.TestHotFixClass, '.ctor' , function(self,p,c,d)
        print("Lua .ctor",p,c,d)
end)

结果:

 

3.属性

method_name 等于 get_属性名,setter 的 method_name 等于 set_属性名。

C#侧代码:

[Hotfix]
[LuaCallCSharp]
public class TestHotFixClass
{
    private int testProperty;

    public int TestProperty{ 
        get {
            return testProperty;
        } 
        set {
            testProperty = value;
            Debug.Log($"c# set {testProperty}");
        } 
    }
}

调用代码:

  TestHotFixClass testHotFixClass = new TestHotFixClass();
  luaenv = new LuaEnv();
  luaenv.AddLoader(customLoader);
  testHotFixClass.TestProperty = 10;
  Debug.Log($"before get {testHotFixClass.TestProperty}");
  luaenv.DoString("require 'main'");
  Debug.Log($"after get {testHotFixClass.TestProperty}");
  testHotFixClass.TestProperty = 100;
  Debug.Log($"set after get {testHotFixClass.TestProperty}");

Lua侧代码:

xlua.hotfix(CS.TestHotFixClass, {  
    set_TestProperty = function(self, v)
        self.testProperty = v
        print('Lua set_TestProperty', v)
    end;
    get_TestProperty = function(self)
        print('Lua get_TestProperty')
        return self.testProperty
    end
})

结果:

 

4.[]操作符

赋值对应 set_Item,取值对应 get_Item。第一个参数是 self,赋值后面跟 key,value,取值只有 key 参数,返回值是取出的值。

C#侧代码:

 public int this[string field]
 {
     get{ return 1;}
     set{}
 }

 public string this[int index]
 {
     get{ return "aaabbbb";}
     set{}
 }

C#侧调用代码:

 Debug.Log(testHotFixClass[1]);
 Debug.Log(testHotFixClass["cc"]);
 luaenv.DoString("require 'main'");
 Debug.Log(testHotFixClass[1]);
 Debug.Log(testHotFixClass["cc"]);

Lua侧代码:

xlua.hotfix(CS.TestHotFixClass, {  
     get_Item = function(self, k)
         print('get_Item', k)
         return 1024
     end;
     set_Item = function(self, k, v)
         print('set_Item', k, v)
     end;
})

结果:

5.其他操作符

使用C#的内部操作符可以覆盖对应函数,比如+号的操作符函数名是 op_Addition,

操作符还有哪些可以看下边这篇文章

C#中如何利用操作符重载和转换操作符 (转载) - PowerCoder - 博客园 (cnblogs.com)

C#代码:

[Hotfix]
[LuaCallCSharp]
public class HotFixOtherOperator
{
    public static int operator +(HotFixOtherOperator a, HotFixOtherOperator b)
    {
        Debug.Log("C# op_add");
        return 0;
    }
}

调用代码:

  HotFixOtherOperator ho1 = new HotFixOtherOperator();
  HotFixOtherOperator ho2 = new HotFixOtherOperator();
  int a = ho1 + ho2;
  luaenv.DoString("require 'main'");

Lua代码:

xlua.hotfix(CS.HotFixOtherOperator,"op_Addition",function(a,b)
         print("Lua Op_add")
         return 0
    end)

local ho1 = CS.HotFixOtherOperator()
local ho2 = CS.HotFixOtherOperator()
local a = ho1 + ho2

结果:

 

6.事件

+= 操作符是 add_事件名-=对应的是 remove_事件名。这两个函数均是第一个参数是self,第二个参数是操作符后面跟的delegate。
C#代码:

[Hotfix]
[LuaCallCSharp]
public class TestHotFixClass
{
    public event Action myEvent;
}

调用代码:

    luaenv.DoString("require 'main'");
    TestHotFixClass testHotFixClass = new TestHotFixClass();
    testHotFixClass.myEvent += TestHotfixEvent;
    testHotFixClass.myEvent -= TestHotfixEvent;

Lua代码:

-- 事件
xlua.hotfix(CS.TestHotFixClass, {  
      ['.ctor'] = function(self)
            util.state(self, {evt = {}})
      end;
      add_myEvent = function(self, cb)
          print('add_Event', cb)
          table.insert(self.evt, cb)
      end;
      remove_myEvent = function(self, cb)
          print('remove_Event', cb)
          for i, v in ipairs(self.evt) do
             if v == cb then
                table.remove(self.evt, i)
             break
             end
         end
     end;
})

结果:

通过 xlua.private_accessible(版本号大于2.1.11不需要调用 xlua.private_accessible)来直接访问,事件对应的私有 delegate 的直接访问后,可以通过对象的"&事件名"字段直接触发事件,例如 self['&MyEvent'](),其中MyEvent是事件名。

7.析构函数

method_name 是 "Finalize",传一个 self 参数。析构函数的热补丁并不是替换,而是开头调用 lua 函数后继续原有逻辑。

C#侧代码:

[Hotfix]
[LuaCallCSharp]
public class TestHotFixClass
{
    ~TestHotFixClass()
    {
        Debug.Log("执行析构函数");
    }
}

调用代码:

     TestHotFixClass testHotFixClass = new TestHotFixClass();
     luaenv = new LuaEnv();
     luaenv.AddLoader(customLoader);
     System.GC.Collect();
     System.GC.WaitForPendingFinalizers();
     luaenv.DoString("require 'main'");
     TestHotFixClass testHotFixClass1 = new TestHotFixClass();
     luaenv.FullGc();
     System.GC.Collect();
     System.GC.WaitForPendingFinalizers();

Lua侧代码:

xlua.hotfix(CS.TestHotFixClass,"Finalize", function(self)
     print('Finalize', self)
end)

结果:

注:System.GC.Collect()

 System.GC.WaitForPendingFinalizers

luaenv.FullGC():清理GC

8.泛型

其他规则一致,每个泛化类型实例化后都是一个独立的类型,只能针对实例化后的类型分别打补丁。

C#代码:

[Hotfix]
public class TestGeneric<T>
{
    public TestGeneric()
    {
        Debug.Log($"aaaaa,{typeof(T)}");
    }
}

调用代码:

TestGeneric<int> testGeneric = new TestGeneric<int>();
TestGeneric<float> testGeneric1 = new TestGeneric<float>();
luaenv.DoString("require 'main'");
TestGeneric<int> testGeneric2 = new TestGeneric<int>();
TestGeneric<float> testGeneric3 = new TestGeneric<float>();

Lua代码:

xlua.hotfix(CS.TestGeneric(CS.System.Int32),".ctor", function(self)
     print("LUA INT32")
end)

xlua.hotfix(CS.TestGeneric(CS.System.Single),".ctor", function(self)
     print("LUA FLAOTG4")
end)

结果:

如果Lua侧没有泛型的单独函数不会报错,只会执行C#侧的泛型函数

TestGeneric<double> testGeneric2 = new TestGeneric<double>();

 

9.Unity协程

通过 util.cs_generator 可以用一个 function 模拟一个 IEnumerator,yield return使用在里头的 coroutine.yield模拟。

C#代码:

[Hotfix]
public class HotFixSubClass : MonoBehaviour
{
    IEnumerator Start()
    {
        while (true)
        {
            yield return new WaitForSeconds(3);
            Debug.Log("C# Wait for 3 seconds");
        }
    }
}

调用代码:

 Unity协程的使用请看3.1节。

C#代码:

[Hotfix]
public class HotFixCoroutine: MonoBehaviour
{
    private void Start()
    {
        StartCoroutine(CoroutineStart());
    }

    IEnumerator CoroutineStart()
    {
        while (true)
        {
            yield return new WaitForSeconds(1);
            Debug.Log("c# Wait for 3 seconds");
        }
    }
}

调用代码:

new GameObject().AddComponent<HotFixCoroutine>();
luaenv.DoString("require 'main'");
new GameObject().AddComponent<HotFixCoroutine>();

Lua代码:

xlua.hotfix(CS.HotFixCoroutine,{
        CoroutineStart = function(self)
            return util.cs_generator(function()
                while true do
                    coroutine.yield(CS.UnityEngine.WaitForSeconds(3))
                    print('Wait for 3 seconds')
                end
            end)
        end;
})

 结果:

10.整个类

如果要替换整个类,使用一个 table,按 method_name = function 组织即可。

注:将打补丁1-9小节挑选合适的填入table({})中

xlua.hotfix(CS.类名, {  
     --放入要热修复的代码
})

3.其他

 1.Unity协程的使用

C#代码:

新建一个MonoBehaviour,

   public class TestCoroutine : MonoBehaviour
   {
   }

添加WaitForSeconds到LuaCallCSshrap的静态列表中,供Lua侧调用

Lua代码:

local gameobject = CS.UnityEngine.GameObject('CoroutineTest')
CS.UnityEngine.Object.DontDestroyOnLoad(gameobject)
local cs_coroutine_runner = gameobject:AddComponent(typeof(CS.TestCoroutine))

local times = 5
cs_coroutine_runner:StartCoroutine(util.cs_generator(function()
    while (times > 0) do
       print('coroutine aaaaa')
	   coroutine.yield(CS.UnityEngine.WaitForSeconds(1))
       times = times - 1
    end
end))

结果:

 

2.Unity脚本

在Lua定义对应Unity的生命周期函数,再从C#侧获取并在对应的生命周期函数执行即可。

C#代码:

 void Awake()
 {   
     。。。。。。。。省略代码。。。。。
     Action luaAwake = scriptEnv.Get<Action>("awake");
     scriptEnv.Get("start", out luaStart);
     scriptEnv.Get("update", out luaUpdate);
     scriptEnv.Get("ondestroy", out luaOnDestroy);

     if (luaAwake != null)
     {
         luaAwake();
     }
 }

 // Use this for initialization
 void Start()
 {
     if (luaStart != null)
     {
         luaStart();
     }
 }

 // Update is called once per frame
 void Update()
 {
     if (luaUpdate != null)
     {
         luaUpdate();
     }
     if (Time.time - LuaBehaviour.lastGCTime > GCInterval)
     {
         luaEnv.Tick();
         LuaBehaviour.lastGCTime = Time.time;
     }
 }

 void OnDestroy()
 {
     if (luaOnDestroy != null)
     {
         luaOnDestroy();
     }
     luaOnDestroy = null;
     luaUpdate = null;
     luaStart = null;
     scriptEnv.Dispose();
 }

Lua侧代码:

function start()

end

function update()

end

function ondestroy()

end

3.UI事件

Lua代码:

self:GetComponent("Button").onClick:AddListener(function()
	print("clicked, you input is '" ..input:GetComponent("InputField").text .."'")
end)

参考链接:

介绍 — XLua (tencent.github.io)


网站公告

今日签到

点亮在社区的每一天
去签到