xLua热更新学习,包括C#与Lua的相互调用

xLua的基础调用

首先在https://gitee.com/OcxnO/XLua该网站下载xLua,然后解压好后将Assets路径下的文件都复制到我们自己的工程目录Assets下

然后就是如何使用:

这是C#执行Lua语句

//Lua是解释型语言,所以需要获得Lua的解析器

//xLua解析器获得

LuaEnv env = new LuaEnv();

//解析器运行Lua代码,把字符串当成lua代码执行

env.DoString("print('hello world!')");

//解析器释放

env.Dispose();

这是Lua调用C#

LuaEnv env = new LuaEnv();

    //Lua调用C#代码(CS.命名空间.类名.方法名(参数))

    env.DoString("CS.UnityEngine.Debug.Log('from lua')");

env.Dispose();

Lua可以返回值给C#

LuaEnv env = new LuaEnv();

     object[] result = env.DoString("return 100, true");

    Debug.Log(result[0]);

     Debug.Log(result[1]);

     env.Dispose();

然后C#可以让一个Lua脚本运行:DoString里填写require(‘Lua脚本名’)

LuaEnv env = new LuaEnv();

        //对应Test.lua

        //内置的加载器会扫描预制的目录,查找是否存在Test.lua,预制目录为StreamingAssets

        //但是为实现热跟新,一般需要把lua脚本放在可修改的一个目录下

        env.DoString("require('Test');");

        env.Dispose();

实现一个自定义加载器,从我们设置的路径加载Lua脚本文件

//自定义加载器

    //自定义加载器会先于系统内置加载器执行,当自定义加载器加载到文件后,后续的加载器不会继续执行

    //当Lua代码执行require()函数时,自定义加载器会尝试获得文件的内容

    //参数为lua脚本的路径

    //如果需要加载的文件不存在,需要返回null

    public byte[] ProjectLoader(ref string filepath)

    {

        //filepath来自于Lua的require(“文件名”)

        //构造路径,才能将require加载的文件指向到我们想放Lua的路径下

        //路径可以任意定制(可以把Lua代码放在AB包内)

        string path = Application.dataPath;

        //Debug.Log(path);

        path = path.Substring(0, path.Length - 7) + "/DataPath/Lua/" + filepath + ".lua";

        //Debug.Log(path);

        

        if(File.Exists(path))

            //将Lua文件读成字节数组

            //xLua的解析环境,会执行我们自定义加载器返回的Lua代码

            return File.ReadAllBytes(path);

        return null;

}

定义好自己的加载器后,要讲加载器添加到xLua 的解析环境中,此时记载Lua文件时优先使用自定义加载器进行加载,若加载到了则默认加载器不执行,否则使用摸人家在其继续加载

LuaEnv env = new LuaEnv();

    //将自定义的加载器加入到xLua 的解析环境中

    env.AddLoader(ProjectLoader);

    env.DoString("require('Test1')");

    env.Dispose();

然后我们可以自己封装一个单例xLuaEnv,避免解析器的重复多次创建

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;

/// <summary>
/// 自己封装的单例
/// </summary>
public class xLuaEnv
{
    private static xLuaEnv _instance;

    private LuaEnv _env;

    private xLuaEnv()
    {
        _env = new LuaEnv();
        _env.AddLoader(_ProjectLoader);
    }

    //单例
    public static xLuaEnv Instance
    {
        get
        {
            if (_instance == null)
                _instance = new xLuaEnv();
            return _instance;
        }
    }

    //释放解析器
    public void DisposeEnv()
    {
        _env.Dispose();
        _instance = null;
    }

    //DoString方法
    public object[] DoString(string code)
    {
        return _env.DoString(code);
    }

    /// <summary>
    /// 返回env中存储的全局变量
    /// Global中存储了Lua中所有定义的全局变量
    /// </summary>
    public LuaTable Global
    {
        get
        {
            return _env.Global;
        }
    }

    //自定义加载器
    //自定义加载器会先于系统内置加载器执行,当自定义加载器加载到文件后,后续的加载器不会继续执行
    //当Lua代码执行require()函数时,自定义加载器会尝试获得文件的内容
    //参数为lua脚本的路径
    //如果需要加载的文件不存在,需要返回null
    private byte[] _ProjectLoader(ref string filepath)
    {
        //filepath来自于Lua的require(“文件名”)
        //构造路径,才能将require加载的文件指向到我们想放Lua的路径下
        //路径可以任意定制(可以把Lua代码放在AB包内)
        string path = Application.dataPath;
        //Debug.Log(path);
        path = path.Substring(0, path.Length - 7) + "/DataPath/Lua/" + filepath + ".lua";
        //Debug.Log(path);

        if (File.Exists(path))
            //将Lua文件读成字节数组
            //xLua的解析环境,会执行我们自定义加载器返回的Lua代码
            return File.ReadAllBytes(path);
        return null;
    }
}

Lua调用C#相关学习

Lua调用C#的静态类

首先在C#中写一个静态类,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#静态类以及类的成员变量和方法
/// </summary>
public class LuaCallCStatic : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallCStatic')");
    }


    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}


namespace C2L
{
    public static class TestStatic
    {
        public static int id = 99;

        public static string name
        {
            get;
            set;
        }

        public static string Output()
        {
            return "C2L";
        }

        public static void Defult(string str = "abc")
        {
            Debug.Log(str);
        }
    }
}

然后在Lua调用这个静态类相关数据

--Lua调用C#学习

--1.Lua调用C#静态类
--规则“CS.命名空间.类名.成员变量”
print(CS.C2L.TestStatic.id);

--给静态属性赋值
CS.C2L.TestStatic.name = "admin";
print(CS.C2L.TestStatic.name);

--静态成员方法调用
--规则“CS.命名空间.类名.方法名()”
print(CS.C2L.TestStatic.Output());

CS.C2L.TestStatic.Defult();
CS.C2L.TestStatic.Defult("TestStatic");

Lua实例化C#的类对象

首先在C#中给一个类,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#对象
/// </summary>
public class LuaCallObject : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallObject')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();   
    }
}

public class Npc
{
    public string Name;
    public int HP
    {
        get;
        set;
    }
    public Npc()
    {

    }

    public Npc(string name)
    {
        this.Name = name;
    }

    public string Output()
    {
        return Name;
    }
}

然后在Lua中实例化这个类对象并使用其数据

--Lua调用C#学习

--2.Lua实例化C#的一个类
--在C#里 Npc obj = new Npc()
--在Lua里的方法: CS.命名空间.对象的构造方法,若没有命名空间可省略
local obj = CS.Npc();


obj.HP = 100;
print(obj.HP);

local obj1 = CS.Npc("admin");
print(obj1.Name);

--表方法希望调用表成员变量(表:函数())
--因为Output返回了对象内的Name,return this.Name 相当于使用了Lua里的self
local name = obj1:Output();
print(name);

--Lua实例化GameObject
--C#实例化GameObject GameObject obj = new GameObject(“name”);
local obj = CS.UnityEngine.GameObject("LuaCreatGO");
print(obj.name);
--使用实例化的C#对象的方法都使用":"
obj:AddComponent(typeof(CS.UnityEngine.BoxCollider));

local engine = CS.UnityEngine;
engine.GameObject("Test");

Lua调用C#的结构体

首先在C#中给一个结构体,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#结构体
/// </summary>
public class LuaCallStruct : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallStruct')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

namespace C2L
{
    public struct TestStruct
    {
        public string Name;

        public string Output()
        {
            return Name;
        }
    }
}

然后在Lua中实例化这个结构体对象并使用其数据

--Lua调用C#学习

--3.Lua调用C#的结构体
--和对象调用保持一致
local obj = CS.C2L.TestStruct();

obj.Name = "admin";

print(obj.Name);

--这里调用结构体对象的方法也是使用":"
local name = obj:Output();
print(name);

Lua调用C#的枚举

首先在C#中给一个枚举,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#枚举
/// </summary>
public class LuaCallEnum : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallEnum')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

namespace C2L
{
    public enum TestEnum
    {
        LOL = 1,
        Dota2
    }
}

然后在Lua中使用这个枚举数据

--Lua调用C#学习

--4.Lua调用C#的枚举
--规则CS.命名空间.枚举名.枚举值
--枚举获得的是userdata自定义数据类型,获得其他语言数据类型时,就是userdata
local enum = CS.C2L.TestEnum.LOL;
print(enum);
print(type(CS.C2L.TestEnum.Dota2));

--转换获得枚举值
print(CS.C2L.TestEnum.__CastFrom(1));
print(CS.C2L.TestEnum.__CastFrom("Dota2"));

Lua调用C#的函数重载

首先在C#中给出几个重载的函数,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#重载函数
/// </summary>
public class LuaCallOverLoad : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallOverLoad')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

namespace C2L
{
    public class TestOverload
    {
        public static void Test(int id)
        {
            Debug.Log("数字类型:" + id);
        }

        public static void Test(string name)
        {
            Debug.Log("字符串类型:" + name);
        }

        public static void Test(int id, string name)
        {
            Debug.Log("两个数值:" + id + "," + name);
        }
    }
}

然后在Lua中调用这些重载函数

--Lua调用C#学习

--5.Lua调用C#函数重载
local overload = CS.C2L.TestOverload;
overload.Test(10);
overload.Test("admin");
overload.Test(50, "mlg");

Lua调用C#中继承相关知识

首先在C#中给出一个父类与子类,分别实现其一些数据与方法,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#继承
/// </summary>
public class LuaCallBase : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallBase')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

namespace C2L
{
    public class Father
    {
        public string Name = "father";

        public void Talk()
        {
            Debug.Log("这是父类的方法");
        }

        public virtual void Overide()
        {
            Debug.Log("这是父类的虚方法");
        }
    }

    public class Child : Father
    {
        public override void Overide()
        {
            Debug.Log("这是子类重写的方法");
        }
    }
}

然后在Lua中实例化父类与子类对象并使用其数据(本质上和Lua实话C#类是一致的)

--Lua调用C#学习

--6.Lua调用C#继承相关
local father = CS.C2L.Father();
print(father.Name);
father:Overide();		--父类的虚方法
father:Talk();

local child = CS.C2L.Child();
print(child.Name);
child:Overide();		--子类重写的方法
child:Talk();

Lua调用C#中类的拓展相关

首先在C#中给出类及其拓展方法,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

/// <summary>
/// Lua调用C#类扩展的方法
/// </summary>
public class LuaCallExtend : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallExtend')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}


namespace C2L
{
    public class TestExtend
    {
        public void Output()
        {
            Debug.Log("类本身带的方法");
        }
    }

    //类扩展,需要给扩展方法编写的静态类添加[LuaCallCSharp]这个特性,否则Lua无法调用到
    [LuaCallCSharp]
    public static class MyExtend
    {
        public static void Show(this TestExtend obj)
        {
            Debug.Log("类扩展的方法");
        }
    }
}

然后在Lua中实例化这个类并调用其拓展方法

--Lua调用C#学习

--7.Lua调用C#类扩展的方法相关
--注意: 类扩展,需要给扩展方法编写的静态类添加[LuaCallCSharp]这个特性,
--否则Lua无法调用到,此特性是在C#脚本中添加的
local extend = CS.C2L.TestExtend();
extend:Output();
extend:Show();

Lua调用C#中的委托,并给委托赋值

首先在C#中给出一个委托,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


/// <summary>
/// Lua调用C#的委托,给委托赋值
/// </summary>
public class LuaCallDelegate : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallDelegate')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

namespace C2L
{
    public delegate void DelegateLua();
    public class TestDelegate
    {
        public static DelegateLua Static;

        public DelegateLua Dynamic;

        public static void StaticFunc()
        {
            Debug.Log("C#静态成员函数");
        }
    }
}

然后在Lua中给这个委托进行赋值,并调用这个委托

--Lua调用C#学习

--8.Lua调用C#委托,给委托赋值
--local delegate = CS.C2L.TestDelegate.Static;		--使用这种方式会有点问题,在进行+或-操作时
CS.C2L.TestDelegate.Static = CS.C2L.TestDelegate.StaticFunc;		--给委托赋值

	
--lua中如果添加量函数到静态委托变量后,
--在委托不再使用后,记得释放添加的委托
--delegate = nil;	

local func = function()
	print("这是Lua的函数");
end

--直接CS.C2L.TestDelegate.Static = func会覆盖原CS.C2L.TestDelegate.StaticFunc
--CS.C2L.TestDelegate.Static = func;
--进行+或-操作时一定要确定已经添加过回调函数
CS.C2L.TestDelegate.Static = CS.C2L.TestDelegate.Static + func;
--CS.C2L.TestDelegate.Static = CS.C2L.TestDelegate.Static - func;
--调用前应确定委托有值
if(CS.C2L.TestDelegate.Static ~= nil) then
	CS.C2L.TestDelegate.Static();
end

CS.C2L.TestDelegate.Static = nil;

--根据委托判定赋值方法
--if(CS.C2L.TestDelegate.Static == nil) 
--then
--	CS.C2L.TestDelegate.Static = func;
--else
--	CS.C2L.TestDelegate.Static = CS.C2L.TestDelegate.Static + func;
--end

local obj = CS.C2L.TestDelegate();
--注意使用对象的委托使用"."
obj.Dynamic = func;
obj.Dynamic();
obj.Dynamic = nil;

Lua调用C#中的事件,并给事件添加方法

首先在C#中给出一个事件,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#的事件
/// </summary>
public class LuaCallEvent : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallEvent')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

namespace C2L
{
    public delegate void DelegateTest();

    public class TestEvent
    {
        public static event DelegateTest Static;

        public event DelegateTest Dynamic;

        public static void StaticFunc()
        {
            Debug.Log("这是静态函数");
        }

        public static void CallStatic()
        {
            if (Static != null)
                Static();
        }

        public void CallDynamic()
        {
            if (Dynamic != null)
                Dynamic();
        }
    }
}

然后在Lua中给这个事件进行赋值,并调用这个事件

--Lua调用C#学习

--9.Lua添加C#的事件
--C#中的实现:TestEvent.Static += TestEvent.StaticFunc
--Lua添加事件(给静态的添加事件)
CS.C2L.TestEvent.Static("+", CS.C2L.TestEvent.StaticFunc)
CS.C2L.TestEvent.CallStatic();
CS.C2L.TestEvent.Static("-", CS.C2L.TestEvent.StaticFunc)

--动态添加成员变量
local func = function()
	print("这是Lua的回调函数");
end

local obj = CS.C2L.TestEvent();
--注意使用对象的事件使用":"
obj:Dynamic("+", func);
obj:CallDynamic()
obj:Dynamic("-", func);

Lua对C#中的泛型的使用

首先在C#中给出一个泛型方法,然后将会用的类型分别实现并调用这个泛型方法,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#的泛型
/// </summary>
public class LuaCallGenericType : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallGenericType')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

namespace C2L
{
    public class TestGenericType
    {
        public void Output<T>(T data)
        {
            Debug.Log("泛型方法:" + data.ToString());

        }

        public void Output(float data)
        {
            Output<float>(data);
        }

        public void Output(string data)
        {
            Output<string>(data);
        }
    }
}

然后在Lua中调用这个方法,也可以通过typeof调用C#中的方法

--Lua调用C#学习

--10.Lua对C#泛型的使用
local obj = CS.C2L.TestGenericType();
obj:Output(99);
obj:Output("admin");

local go = CS.UnityEngine.GameObject("LuaCreate");
--xLua实现了typeof关键字,所以可以使用类型API替代unity内置的泛型方法
go:AddComponent(typeof(CS.UnityEngine.BoxCollider))

Lua对C#中的out,ref的使用

首先在C#中给出一些带有out,ref参数的方法,然后在生命周期函数中使用封装好的单例加载Lua文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua对C#的out和ref的使用
/// </summary>
public class LuaCallOutRef : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("require('C#2Lua/LuaCallOutRef')");
    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

namespace C2L
{
    public  class TestOutRef
    {
        public static string Func1()
        {
            return "Func1";
        }

        public static string Func2(string str1, out string str2)
        {
            str2 = "Func2 out";
            return "Func2";
        }

        public static string Func3(string str1, ref string str2)
        {
            str2 = "Func3 Ref";
            return "Func3";
        }

        public static string Func4(ref string str1, string str2)
        {
            str1 = "Func4 Ref";
            return "Func4";
        }
    }
}

然后在Lua中调用这些方法

--Lua调用C#学习

--11.Lua对C#out和ref的使用
local func1 = CS.C2L.TestOutRef.Func1();
print(func1);

--注意C# out返回的变量会赋值给Lua的第二个接收返回值的变量
--此时out为nil,func2为函数返回值Func2,out1为函数out出的值Func2 out
local out;
local func2, out1 = CS.C2L.TestOutRef.Func2("admin", out);
print(func2, out1,out);

--注意C# ref返回的变量会赋值给Lua的第二个接收返回值的变量,与out一致
--此时ref2为nil,func3为函数返回值Func3,ref1为函数ref出的值Func3 Ref
local ref2;
local func3, ref1 = CS.C2L.TestOutRef.Func3("root", ref2);
print(func3, ref1,ref2);

--即使out,ref作为第一个参数,其结果依然会以Lua 的多返回值进行返回
--结果与上面一致
local ref4;
local func4, ref3 = CS.C2L.TestOutRef.Func4(ref4, "test");
print(func4, ref3, ref4);

C#获取Lua中的全局变量

首先在Lua脚本中定义一些全局变量

--定义全局变量时,隐性的做了{num=100,rate=99.99,isWoman=false,name="admin"}
--这个表是全局的
num = 100;
rate = 99.99;
isWoman = false;
name = "admin";

然后在C#中获取这些全局变量并使用

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

/// <summary>
/// C#获取Lua的全局变量
/// </summary>
public class CSharpCallVariable : MonoBehaviour
{
    void Start()
    {
        //Lua中代码为return 100
        //调用require('Lua2C#/CSharpCallVariable'),是让Lua中返回100,要想接收到返回值,此代码前还要加一个return,即return require('Lua2C#/CSharpCallVariable')
        //object[] value = xLuaEnv.Instance.DoString("return require('Lua2C#/CSharpCallVariable')");

        //Debug.Log(value[0]);


        //LuaEnv中提供了一个成员变量Global,它用于C#获取Lua的全局变量
        //Global的数据类型时C#实现的LuaTable,LuaTable时xLua实现C#和Lua中表对应的数据结构
        //xLua会将Lua中的全局变量以Table的方式全部存储在Global中
        xLuaEnv.Instance.DoString("require('Lua2C#/CSharpCallVariable')");

        //通过运行环境,到处全局变量,类型为LuaTable
        //LuaTable是C#的数据对象,用于和Lua中的全局变量存储的Table对应
        LuaTable g = xLuaEnv.Instance.Global;

        //从Lua中,将全局变量提取出来
        //参数:Lua中全局变量的名称
        //类型:Lua中全局变量的名称所对应的类型
        //返回值:变量的值
        Debug.Log(g.Get<int>("num"));
        Debug.Log(g.Get<float>("rate"));
        Debug.Log(g.Get<bool>("isWoman"));
        Debug.Log(g.Get<string>("name"));

    }

    // Update is called once per frame
    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

C#获取Lua中的方法

首先在Lua脚本中定义一些方法

func1 = function()
	print("这是Lua中的func1");
end

func2 = function(name)
	print("这是Lua中的func2,参数是:"..name);
end

func3 = function()
	return "这是Lua中的func3";
end

func4 = function()
	return "这是Lua中的func4", 100;
end

然后在C#中调用这些方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

public delegate void Func1();

public delegate void Func2(string name);

public delegate string Func3();

[CSharpCallLua]//映射产生时,xLua提示添加的
public delegate void Func4(out string name, out int id);

//C#调用Lua的函数方法
public class CSharpCallFunction : MonoBehaviour
{
    void Start()
    {
        xLuaEnv.Instance.DoString("return require('Lua2C#/CSharpCallFunction')");

        LuaTable g = xLuaEnv.Instance.Global;
        //Lua的函数,会导出为C#的委托类型
        Func1 func1 = g.Get<Func1>("func1");
        func1();

        //向Lua函数传递数据
        Func2 func2 = g.Get<Func2>("func2");
        func2("admin");

        //接收Lua函数的返回值
        Func3 func3 = g.Get<Func3>("func3");
        Debug.Log(func3() + ",被C#打印");

        //Lua多返回值
        Func4 func4 = g.Get<Func4>("func4");
        string name;
        int id;
        func4(out name, out id);
        Debug.Log(name + "," + id);
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

C#获取Lua中的表

首先在Lua脚本中定义一个表及其数据方法

Core = {}
Core.ID = 100;
Core.Name = "root";
Core.IsWoman = false;

Core.Func1 = function(name)
	print("这是Core表的Func1函数,接收到C#数据为:"..name);
end

Core.Func2 = function()
	return "这是Core表的Func2函数";
end

Core.Func3 = function(self)
	print("这是Core表的Func3函数,Core表的成员变量Name是:"..self.Name);
end

function Core:Func4()
	print("这是Core表的Func4函数,Core表的成员变量Name是:"..self.Name);
end

然后在C#获取这个表数据并使用

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

public delegate void OneStringParams(string name);
public delegate void TransSelf(LuaTable table);
public delegate string OneStringReturn();
[CSharpCallLua]
public delegate void TransMy(LuaCore table);

//实现了Lua的Table导出到C#的结构体,可以实现C#运行时无GC
[GCOptimize]
public struct LuaCore
{
    public int ID;
    public string Name;
    public bool IsWoman;

    public OneStringParams Func1;
    public OneStringReturn Func2;
    public TransMy Func3;
    public TransMy Func4;
}

public class CSharpCallTable : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        xLuaEnv.Instance.DoString("require('Lua2C#/CSharpCallTable')");

        //UseLuaTable();
        UseStruct();
    }

    //直接拿到Lua中table内的各个数据
    public void UseLuaTable()
    {
        LuaTable g = xLuaEnv.Instance.Global;
        //获得的是全局变量Core,因为它在Lua中是表,所以取出来的是LuaTable类型
        LuaTable core = g.Get<LuaTable>("Core");
        //获取Name
        //参数:table中索引名
        //类型:索引对应值得类型
        Debug.Log(core.Get<string>("Name"));

        core.Set<string, string>("Name", "admin");

        OneStringParams osp = core.Get<OneStringParams>("Func1");
        osp("admin");

        //相当于":"调用
        TransSelf ts = core.Get<TransSelf>("Func4");
        ts(core);
    }

    //将Lua中的表导出为C#中的结构体LuaCore,然后就直接使用这个结构体即可
    public void UseStruct()
    {
        LuaTable g = xLuaEnv.Instance.Global;

        //将Lua的table导出为LuaCore结构体
        LuaCore core = g.Get<LuaCore>("Core");

        Debug.Log(core.Name);
        core.Func4(core);
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.DisposeEnv();
    }
}

xLua的拓展学习可查看网址

简介 · GitBook

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值