XLua教程

热更新相关参考文档

XLua下载地址,下载后的文件中有官方教程文档

XLua版本:2.1.15 Unity版本:2019.4.25f1c1

Lua文件的加载

XLua下载后,将XLua文件中的Assets文件夹下的文件放到项目中的Assets文件下,就完成了XLua的安装。

若要使用Xlua代码需要引用XLua的命名空间:using XLua

  • 系统加载器和自定义加载器加载Lua文件
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;
/// <summary>
/// 加载Lua中的模块:使用require()函数
/// 加载器:因为Lua是多脚本编写方式,所以经常会使用require(),加载子文件
/// 加载器是xLua实现了一种方式,可以由C#来控制require()函数加载Lua文件
/// </summary>
public class Loder : MonoBehaviour
{
    private void OnGUI()
    {
        if (GUILayout.Button("系统lua文件加载")){ SystemLoader(); }
        if (GUILayout.Button("自定义lua文件加载")){ MyLoader(); }
        if (GUILayout.Button("利用构造器进行文件加载")){ MyLoaderWithSingleton(); }
    }
    //使用系统的加载器加载Lua文件
    private void SystemLoader()
    {
        //Lua是解释型语言,所以需要获得Lua的解析器
        //获得xlua解析器 LuaEnv
        LuaEnv luaEnv = new LuaEnv();
        //解析器运行Lua代码,使用DoString()方法把字符串当成Lua代码执行
        luaEnv.DoString("print('Hello World')")//执行后打印Hello World
        //内置加载器会扫描预制的目录,查找是否存在test.lua;
        //xLua存在默认加载器,在StreamingAssets目录下加载文件
        luaEnv.DoString("require('test')");//执行lua代码:调用require函数加载模块,加载成功执行test中的Lua脚本
        //解析器释放
        luaEnv.Dispose();
    }
    //自定义加载器加载Lua文件
    private void MyLoader()
    {
        LuaEnv luaEnv = new LuaEnv();
        //AddLoader():添加自定义加载器
        //AddLoader所需要的参数是一个委托:public delegate byte[] CustomLoader(ref string filepath);
        //所以传参时,需要传入一个与委托有相同签名的方法
        luaEnv.AddLoader(ProjectLoader);
        luaEnv.DoString("require('Lua/test01')");
        luaEnv.Dispose();
    }
    /// <summary>
    /// 自定义加载器,会先于系统内置加载器执行,当自定加载器加载到文件后,后续的加载器则不会继续执行
    /// 自定义Lua文件加载器。当Lua代码执行require()函数时,自定义加载器会尝试获取文件的内容
    /// 路径可以自己定制,可以将Lua放入ab包中
    /// </summary>
    /// <param name="filepath">DoString方法中的Lua方法require中传入的文件路径</param>
    /// <returns>所加载文件的字节格式</returns>
    public byte[] ProjectLoader(ref string filepath)
    {
        #region 构造路径,将require加载的文件指向到我们想放Lua的路径下去
        string dataPath = Application.dataPath;
        dataPath = dataPath.Substring(0,
            Application.dataPath.Length - 6) + "DataPath/" + filepath + ".lua";//路径根据所需进行更改
        #endregion
        Debug.Log(filepath);
        if (File.Exists(dataPath))//是否存在改路径
        {
            //将Lua文件读取为字节数组
            //xLua的解析环境,会执行我们自定义加载器返回的Lua代码
            return File.ReadAllBytes(dataPath);//读取路径下的文件的值以字节形式返回
        }
        else
        {
            return null;
        }
    }
}
  • XLua的单例类
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;

/// <summary>
/// XLua的单例类
/// </summary>
public class XLuaSingleton
{
    private LuaEnv luaEnv;
    private static XLuaSingleton instance;
    public static XLuaSingleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new XLuaSingleton();
                return instance;
            }
            else
            {
                return instance;
            }
        }
    }
    /// <summary>
    /// 私有构造函数;防止在外部被实例化
    /// </summary>
    private XLuaSingleton()
    {
        luaEnv = new LuaEnv();
        luaEnv.AddLoader(ProjectLoader);//添加自定义加载器
    }
    /// <summary>
    /// 自定义加载器,会先于系统内置加载器执行,当自定加载器加载到文件后,后续的加载器则不会继续执行
    /// 自定义Lua文件加载器。当Lua代码执行require()函数时,自定义加载器会尝试获取文件的内容
    /// 路径可以自己定制,可以将Lua放入ab包中
    /// </summary>
    /// <param name="filepath">DoString方法中的Lua方法require中传入的文件路径</param>
    /// <returns>所加载文件的字节格式</returns>
    private byte[] ProjectLoader(ref string filepath)
    {
        #region 构造路径,将require加载的文件指向到我们想放Lua的路径下去
        //Application.dataPath只适用于编辑器模式下
        string dataPath = Application.dataPath;
        dataPath = dataPath.Substring(0,
            Application.dataPath.Length - 6) + "DataPath/" + filepath + ".lua";//路径根据所需进行更改
        #endregion
        Debug.Log(filepath);
        if (File.Exists(dataPath))
        {
            //将Lua文件读取为字节数组
            //xLua的解析环境,会执行我们自定义加载器返回的Lua代码
            return File.ReadAllBytes(dataPath);//读取路径下的文件的值以字节形式返回
        }
        else
        {
            return null;
        }
    }
    /// <summary>
    /// Xlua解析器释放
    /// </summary>
    public void Free()
    {
        instance = null;
        luaEnv.Dispose();
    }
    /// <summary>
    /// 使用DoString方法调用Lua脚本
    /// </summary>
    /// <param name="codefilepath">require('Lua脚本路径')</param>
    /// <returns></returns>
    public object[] DoString(string codefilepath)
    {
        return luaEnv.DoString(codefilepath);
    }
    /// <summary>
    /// 返回一个全局表,用于存储Lua中所有的全局变量组成的table
    /// </summary>
    public LuaTable Global
    {
        get
        {
            return luaEnv.Global;
        }
    }
}

XLua中Lua调用C#

C#实现的功能,可以完全换成Lua实现,因为Lua为脚本语言,可以即时更改,即时运行,所以游戏的代码逻辑就可以随时修改。Lua调用Unity的各种API,从而实现与C#开发获取同样的效果。

Lua调用C#中的Static静态成员

//C#:
using UnityEngine;
using XLua;
/// <summary>
/// Lua调用C#中的静态成员
/// </summary>
namespace CToL
{
    static class StaticTest
    {
        static StaticTest()
        {
            Debug.Log("调用了静态构造函数");
        }
        public static int id = 99;
        public static string Output()
        {
            return "OutPut";
        }
        public static void Print(string name = "123")//用于默认参数,传参时如果默认参数合适可以使用默认参数
        {
            Debug.Log(name);
        }
    }
}
public class LuaCallCStatic : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCStatic')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}

--Lua:
--使用Lua调用C#静态成员:
--规则:CS.命名空间.类名.静态成员,如果没有命名空间,命名空间可以省略

--调用静态字段
print(CS.CToL.StaticTest.id)
--更改静态字段值
CS.CToL.StaticTest.id=18110
print(CS.CToL.StaticTest.id)
--调用静态方法
print(CS.CToL.StaticTest.Output())

--CS.CToL.StaticTest.StaticTest()
--如果执行调用静态构造函数报错:attempt to call a nil value (field 'StaticTest')尝试访问一个空值
--在Lua调用C#静态构造函数时,静态构造函数的执行顺序与在C#中的执行顺序相同,都是在类被调用时执行,详见最终输出结果

CS.CToL.StaticTest.Print()
CS.CToL.StaticTest.Print("ABC")
-------------------------------
//最终输出结果:
调用了静态构造函数
LUA:99
LUA:18100
LUA:OutPut
123
ABC

Lua调用C#中的Object对象

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 使用Lua调用C#对象
/// </summary>
class ObjectTest
{
    public string name;
    public int HP { get; set; }
    public ObjectTest()
    {

    }
    public ObjectTest(string name)
    {
        this.name = name;
    }
    public string Output()
    {
        return name;
    }
}
public class LuaCallCObject : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCObject')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--Lua调用C#中对象
--Lua中创建对象使用CS.命名空间.构造函数
--只有对象和结构体的函数的调用是使用冒号“:”
--其他使用点“.”
local obj01=CS.ObjectTest()--通过调用构造函数创建对象
obj01.HP = 100 --为实例中的成员变量赋值
print(obj01.HP)
local obj02=CS.ObjectTest("ABC")--通过调用有参构造函数创建对象
print(obj02.name)
--**Lua中表调用表中的成员方法:表:函数()**
-- 为什么是冒号,对象引用成员方法时,会隐形调用this,在Lua中this等同于Lua中的self,所以在Lua中使用冒号“:”来调用成员函数
print(obj02:Output())--调用对象中的成员函数时需要使用冒号“:”,而不是点“.”

--使用Lua实例化GameObject
local go = CS.UnityEngine.GameObject("LuaCreateGO")
go:AddComponent(typeof(CS.UnityEngine.BoxCollider))
--调用UnityAPI,创建游戏对象实例
-------------------------------
//最终输出结果:
LUA:100
LUA:ABC
LUA:ABC
 在层级面板上创建出一个名为LuaCreateGO的游戏对象并挂有碰撞器组件

Lua调用C#中的Struct结构体

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#结构体
/// </summary>
public struct StructTest
{
    public string name;
    public void Output()
    {
        Debug.Log(name);
    }
}
public class LuaCallCStruct : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCStruct')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--lua
--Lua调用C#结构体,与调用对象的方式相同
--CS.命名空间.结构体的构造函数
local obj01=CS.StructTest();
obj01:Output();--调用方法,使用冒号“:”与对象调用方法相同
obj01.name="123"--调用变量
obj01:Output();
local obj02=CS.StructTest();
obj02:Output();
obj02.name="abc"
obj02:Output();
--type()获取数据类型
print(type(CS.StructTest()))--userdata
print(type(CS.StructTest))--table,C#的结构体在Lua中的数据类型为Table
-------------------------------
//最终输出结果:
Null
123
Null
abc
LUA:userdata
LUA:table

Lua调用C#中的enum枚举

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#枚举
/// </summary>
namespace EnumNS
{
    public enum EnumTest
    {
        LoL = 0,
        Data2
    }
}
public class LuaCallCEnum : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCEnum')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--Lua调用C#枚举
--CS.命名空间.枚举名.枚举值
--获取C#枚举中的值在Lua中的数据类型为userdata
--userdata自定义数据类型
print(type(CS.EnumNS.EnumTest.Data2))
--获取C#枚举在Lua中的数据类型为table
print(type(CS.EnumNS.EnumTest))
print(CS.EnumNS.EnumTest.LoL)

--通过转换获取枚举值   __CastFrom方法,可以实现从一个整数或者字符串到枚举值的转换
print(CS.EnumNS.EnumTest.__CastFrom(0))
print(CS.EnumNS.EnumTest.__CastFrom('Data2'))
-------------------------------
//最终输出结果:
LUA:userdata
LUA:table
LUA:LoL:0
LUA:LoL:0
LUA:Data2:1

Lua调用C#中的OverLoad方法重载

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#重载,支持C#重载
/// </summary>
public class OverLoad
{
    public static void OverLoadTest(int i)
    {
        Debug.Log("数值类型参数:" + i);
    }
    public static void OverLoadTest(string str)
    {
        Debug.Log("字符串类型参数:" + str);
    }
    public static void OverLoadTest(float f, string str)
    {
        Debug.Log("数值类型与字符类型参数:" + f + "+" + str);
    }
}
public class LuaCallCOverLoad : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCOverLoad')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--Lua调用C#重载
CS.OverLoad.OverLoadTest(123)
CS.OverLoad.OverLoadTest('abc')
CS.OverLoad.OverLoadTest(123.3,"ABC")
-------------------------------
//最终输出结果:
数值类型参数:123
字符串类型参数:abc
数值类型与字符类型参数:123.3+ABC
//注意:xlua只一定程度上支持重载函数的调用,因为lua的类型远远不如C#丰富,存在一对多的情况,
//比如C#的int,float,double都对应于lua的number,
//上面的例子中OverLoadTest如果有这些重载参数,第一行将无法区分开来,只能调用到其中一个(生成代码中排前面的那个)?

Lua调用C#中的继承

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#继承
/// </summary>
public class Father
{
    public string name = "A";
    public void Talk()
    {
        Debug.Log("父类中的Talk方法");
    }
    public virtual void Overide()
    {
        Debug.Log("父类的被重写方法");
    }
}
public class Children : Father
{
    public override void Overide()//进行方法重写,修改父类方法表地址使其执行子类,实现调父执行子
    {
        //base.Overide();//base.父类虚方法:可执行父类中的方法
        Debug.Log("子类重写父类方法");
    }
}
public class LuaCallCInherit : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCInherit')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--Lua调用C#中的继承
--通过CS.构造函数的方法创建实例
local obj01=CS.Father()
print(obj01.name)
obj01:Overide()
local obj02=CS.Children()
obj02:Talk()
obj02:Overide()
-------------------------------
//最终输出结果:
LUA:A
父类的被重写方法
父类中的Talk方法
子类重写父类方法
//xlua支持(通过派生类)访问基类的静态属性,静态方法,(通过派生类实例)访问基类的成员属性,成员方法

Lua调用C#中的方法扩展

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
/// <summary>
/// 方法,类的扩展
/// </summary> 
public class ExtendTest
{
    public void Output()
    {
        Debug.Log("ExtendTest中的Output方法");
    }
}
[LuaCallCSharp]--在被扩展的类前加需要添加特性:[LuaCallCSharp]
public static class Extend
{
    static Extend()
    {
        Debug.Log("Extend的静态构造函数");
    }
    public static string Print(this ExtendTest extendTest)
    {
        return "对ExtendTest进行扩展";
    }
}
public class LuaCallCExtend : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCExtend')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--Lua中调用C#中的方法扩展
local obj01=CS.ExtendTest()
obj01:Output()
print(obj01:Print())
print(CS.Extend.Print())--当调用类的扩展方法时,直接可以通过类名或类的实例进行调用扩展方法。
-------------------------------
//最终输出结果:
ExtendTest中的Output方法
Extend的静态构造函数
LUA:对ExtendTest进行扩展
LUA:对ExtendTest进行扩展

Lua调用C#中的delegate委托

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#委托
/// </summary>
public delegate void LuaDelegate();//定义一个无参无返回值的委托
public class DelegateTest
{
    public static LuaDelegate luaDelegateStatic;//定义一个静态委托变量
    public LuaDelegate luaDelegateDynamic;//定义一个实例委托变量
    public static void StaticFun()
    {
        Debug.Log("C#静态委托调用了静态方法");
    }
}
public class LuaCallCDelegate : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCDelegate')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--Lua调用C#中的委托
--1.Lua调用C#中静态委托
CS.DelegateTest.luaDelegateStatic=CS.DelegateTest.StaticFun--对委托进行注册
CS.DelegateTest.luaDelegateStatic()--委托的调用
--Lua中如果添加了函数到静态委托变量中
--当委托不在使用后,需要释放委托变量中的函数
CS.DelegateTest.luaDelegateStatic=nil

--在C#委托中添加Lua的函数
local fun = function()
	print("这是Lua的函数")
end

if(CS.DelegateTest.luaDelegateStatic == nil)
then
	CS.DelegateTest.luaDelegateStatic = fun--添加委托
else
    --在Lua中实现多播委托,因为在Lua中不支持+=、-=等复合运算符,所以用一下方法实现:
	CS.DelegateTest.luaDelegateStatic = CS.DelegateTest.luaDelegateStatic + fun 
end
	CS.DelegateTest.luaDelegateStatic = CS.DelegateTest.luaDelegateStatic + fun
	CS.DelegateTest.luaDelegateStatic = CS.DelegateTest.luaDelegateStatic - fun
--调用委托和增减委托时需要进行判空操作
if(CS.DelegateTest.luaDelegateStatic~=nil)
then
	--调用委托,此时委托链中只有一个名为fun的函数
	CS.DelegateTest.luaDelegateStatic()
end
CS.DelegateTest.luaDelegateStatic = nil
--2.Lua调用C#实例委托
local obj01=CS.DelegateTest() --创建委托实例
--对委托进行方法注册
obj01.luaDelegateDynamic = CS.DelegateTest.StaticFun
obj01.luaDelegateDynamic = obj01.luaDelegateDynamic + fun
--调用委托
print("调用实例委托:")
obj01.luaDelegateDynamic()
--对委托进行方法注销
--不进行方法注销也不会报错
obj01.luaDelegateDynamic = nil;
-------------------------------
//最终输出结果:
C#静态委托调用了静态方法
LUA:这是Lua的函数
LUA:调用实例委托:
C#静态委托调用了静态方法
LUA:这是Lua的函数

Lua调用C#中的event事件

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

/// <summary>
/// Lua调用C#方法,
/// 在事件的定义类外只能进行事件的注册与注销,如果需要调用则要在类内定义一个对外的调用接口,更加安全,体现了封装的思想
/// </summary>
public delegate void LuaEventHandler();//定义委托
public class EventTest
{
    public static event LuaEventHandler luaEventStatic;
    public event LuaEventHandler luaEventDynamic;//根据委托定义事件
    public void DynamicFunc()
    {
        Debug.Log("调用了实例函数");
    }
    public static void StaticFunc()
    {
        Debug.Log("调用了静态函数");
    }
    public static void CallStatic()//调用静态的事件
    {
        if (luaEventStatic != null)
        {
            luaEventStatic();//调用事件
        }
    }
    public void CallDynamic()//调用实例的事件
    {
        if (luaEventDynamic!=null)
        {
            luaEventDynamic();//调用事件
        }
    }
}
public class LuaCallCEvent : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCEvent')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--Lua调用C#事件,通过方法对事件加值
--增加事件回调
--testobj:TestEvent('+', lua_event_callback)
--移除事件回调
--testobj:TestEvent('-', lua_event_callback)
local function func()
	print("Lua中的输出")
end
--静态
--Lua添加事件
--事件的注册
CS.EventTest.luaEventStatic("+",CS.EventTest.StaticFunc)
CS.EventTest.luaEventStatic("+",func)
CS.EventTest.CallStatic()
--事件的注销
CS.EventTest.luaEventStatic("-",CS.EventTest.StaticFunc)
CS.EventTest.luaEventStatic("-",func)
-- 需要对静态事件进行注销操作,否则,当程序结束时报错:try to dispose a LuaEnv with C# callback!
--实例
local obj01=CS.EventTest()
obj01:luaEventDynamic("+",func)
--无法注册C#中的实例方法??
--obj01:luaEventDynamic("+",obj01:DynamicFunc())
obj01:CallDynamic()
--obj01:luaEventDynamic("-",obj01:DynamicFunc())
-------------------------------
//最终输出结果:
调用了静态函数
LUA:Lua中的输出
LUA:Lua中的输出

Lua调用C#中的GenericType泛型

//C#
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#泛型
/// 在Lua中不支持泛型,如果要在Lua中调用泛型,需要在C#中对泛型给定指定类型并进行封装:像Lua调用C#中的方法一样调用,如下:
/// </summary>
public class GenericTest
{
    private T Output<T>(T output)
    {
       Debug.LogFormat("参数类型为:{0},值为:{1}", typeof(T), output);
       return default;
    }
    public void Output(string str)
    {
        Output<string>(str);
    }
    public void Output(float f)
    {
        Output<float>(f);
    }
}
public class LuaCallCGenericType : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCGenericType')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }

}
--Lua:
--Lua调用C#泛型
local obj01=CS.GenericTest()
obj01:Output("abc")
obj01:Output(123)

local go = CS.UnityEngine.GameObject("LuaCreate")
-- xLua实现了typeof关键字,所以可以用类型API替代Unity内置的泛型方法
go:AddComponent(typeof(CS.UnityEngine.BoxCollider))
-------------------------------
//最终输出结果:
参数类型为:System.String,值为:abc
参数类型为:System.Single,值为:123
 在层级面板上创建出一个名为LuaCreate的游戏对象并挂有碰撞器组件

Lua调用C#中的out ref参数

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Lua调用C#中的out ref
/// </summary>
class OutRefTest
{
    public static void Func01()
    {
        Debug.Log("调用了Func01");
    }
    public static string Func02(out string data, string data1)
    {
        data = "out : Func02-ABC";
        return "调用了Func02";
    }
    public static string Func03(ref string data,string data1)
    {
        data = "ref : Func03-ABC";
        return "调用了Func03";
    }
    public static string Func04(out string data,ref float data01)
    {
        data01 = 190.0f;
        data = "out : Func04-ABC";
        return "调用了Func04";
    }
}
public class LuaCallCOutRef : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('CSharpToLua/LuaCallCOutRef')");
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--Lua调用C#Out Ref

--以out,ref修饰的参数,在Lua中最终都以返回值的形式返回并存储
CS.OutRefTest.Func01()--调用了Func01
--C# out返回的变量,在Lua中会赋值给最后一个接收的变量
local out1
out2,out3 = CS.OutRefTest.Func02(out1,'123')
print(out1,out2,out3)
--C# ref返回的变量,在Lua中会赋值给最后一个接收的变量
local ref1
ref2,ref3= CS.OutRefTest.Func03(ref1,'ABC')
print(ref1,ref2,ref3)
--out先于ref返回值
return1,out4,ref4 = CS.OutRefTest.Func04()
print(return1,out4,ref4)
return2,ref3 = CS.OutRefTest.Func04("test",ref4)
print(return2, ref3, ref4)
-------------------------------
//最终输出结果:
调用了Func01
LUA: nil	调用了Func02	out : Func02-ABC
LUA: nil	调用了Func03	ref : Func03-ABC
LUA: 调用了Func04		out : Func04-ABC	190.0
LUA: 调用了Func04		out : Func04-ABC	190.0

XLua中C#访问Lua

C#调用Lua中的变量

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

/// <summary>
/// C#调用Lua中的变量
/// </summary>
public class CSharpCallLVariable : MonoBehaviour
{
    void Start()
    {
        object[] dataArr = XLuaSingleton.Instance.DoString("return require('LuaToCSharp/CSharpCallLVariable')");
        Debug.Log("Lua中return 的值:" + dataArr[0]);//使用return require()来获取Lua中的返回值        

        //XLua中的LuaEnv类提供一个成员变量Global,使用该变量可以利用XLua通过C#语言获取Lua中的全局变量
        //Global的返回值是LuaTable;LuaTable是由XLua在C#中对Lua中Table(表)的映射
        //Xlua会将Lua中的全局变量以Table的方式存储在LuaTable中。在Lua中会隐性的将所有全局变量存储在Table中

        //获取Lua文件中的全局变量隐性组成的Table,并存储在LuaTable类型的变量中
        LuaTable luaTable = XLuaSingleton.Instance.Global;
        //将Lua中的全局变量提取出来:方法:LuaTable类型变量.Get<变量类型>("Lua中变量名称");
        //参数:Lua中全局变量的名称、类型:Lua中该名称的全局变量的类型、返回值:变量的值
        int intNum = luaTable.Get<int>("intNum");
        float floatNum = luaTable.Get<float>("floatNum");
        string str = luaTable.Get<string>("str");
        bool isBool = luaTable.Get<bool>("isBool");

        Debug.Log("Lua中的intNum:" + intNum);
        Debug.Log("Lua中的floatNum:" + floatNum);
        Debug.Log("Lua中的str:" + str);
        Debug.Log("Lua中的isBool:" + isBool);
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--C#调用Lua的变量

--C#会隐性的将Lua中的全局变量封装为一个表Table,
--通过XLua中使用C#封装的Global变量获取该表并使用LuaTable来存储
--{intNum = 123,floatNum = 123.123,str = 'ABC',isBool = false}

intNum = 123
floatNum = 123.123
str = 'ABC'
isBool = false
return 100
-------------------------------
//最终输出结果:
Lua中return 的值:100
Lua中的intNum:123
Lua中的floatNum:123.123
Lua中的str:ABC
Lua中的isBool:false

C#调用Lua中的方法

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

/// <summary>
/// C#访问Lua中的函数
/// </summary>
///Lua中的方法对应C#中的枚举
public delegate void Func01();//无参无返回值的枚举
public delegate void Func02(string name);//有参无返回值
public delegate string Func03();//有返回值无参
[CSharpCallLua]//映射产生时,xLua提示添加的否则报错
public delegate void Func04(out string str, out int num);//对应Lua中多返回值函数
public class CSharpCallLFunction : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('LuaToCSharp/CSharpCallLFunction')");
        LuaTable luaTable = XLuaSingleton.Instance.Global;
        //Lua函数,会导出为C#的委托类型,且Lua的签名应该与相对应C#委托的签名相同
        Func01 func01 = luaTable.Get<Func01>("func01");
        func01();
        Func02 func02 = luaTable.Get<Func02>("func02");
        func02("zhang");
        Func03 func03 = luaTable.Get<Func03>("func03");
        string str = func03();
        Debug.Log(str);
        Func04 func04 = luaTable.Get<Func04>("func04");
        int data;
        string str1;
        func04(out str1, out data);
        Debug.Log(str1 + "," + data);
    }
    void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--C#调用Lua中的函数
print('C#调用Lua中的函数')

function func01()
	print("这是Lua中的func01")
end
func02 = function(name)
	print("这是Lua中的Func02,参数是:"..name)
end
func03 = function()
	return '这是Lua中的func03'
end
func04 =function()
	return '这是Lua中的func04',100
end
-------------------------------
//最终输出结果:
LUA:C#调用Lua中的函数
LUA:这是Lua中的func01
LUA:这是Lua中的Func02,参数是:zhang
这是Lua中的func03
应该输出的结果:这是Lua中的func04,100
实际报错:InvalidCastException: This type must add to CSharpCallLua: Func04,但是按照错误更改后仍有错
最终解决:在编辑器的菜单栏中点击:XLua-->Generate Code,猜测原因:C#中无法正常识别CSharpCallLua特性,在不生成相关代码的情况下。

C#调用Lua中的表table

//C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

/// <summary>
/// C#调用Lua中的表
/// </summary>
public delegate void OneStringParams(string name);//对应Lua中有一个参数的方法
public delegate void TransSelf(LuaTable luaTable);//对应Lua中self调用
public delegate string OneStringReturn();//结构体中所对应Lua的函数
[CSharpCallLua]//映射产生时,xLua提示添加的否则报错,若添加后仍报错:在编辑器的菜单栏中点击:XLua-->Generate Code
public delegate void TransMy(LuaStruct luaStruct);//对应Lua中self调用
//Lua的Table导出到C#的结构体

//xLua复杂值类型(struct)的默认传递方式是引用传递,这种方式要求先对值类型boxing,传递给lua,
//lua使用后释放该引用。由于值类型每次boxing将产生一个新对象,当lua侧使用完毕释放该对象的引用时,则产生一次gc。
[GCOptimize]//[GCOptimize特性:可以实现C#运行时无GC(垃圾回收器)
//struct配置了GCOptimize属性(对于常用的UnityEngine的几个struct:* Vector系列,Quaternion,Color...均已经配置了该属性),这个属性可以通过配置文件或者C# Attribute实现;
public struct LuaStruct
{
    public int ID;
    public string Name;
    public bool IsMan;

    public OneStringParams Func1;
    public TransSelf Func3;
    public OneStringReturn Func2;
    [CSharpCallLua]
    public TransMy Func4;
}
class CSharoCallLTable : MonoBehaviour
{
    void Start()
    {
        XLuaSingleton.Instance.DoString("require('LuaToCSharp/CSharpCallLTable')");
        //UseLuaTable();
        UseStruct();
    }
    //使用结构体映射Lua中的table
    private void UseStruct()
    {
        //获取全局表LuaTable用于存储Lua中的Table
        LuaTable luaTable = XLuaSingleton.Instance.Global;
        LuaStruct luaCoreStruct = luaTable.Get<LuaStruct>("Core");
        Debug.Log("通过结构体存储Lua中的表中的ID:" + luaCoreStruct.ID);
        luaCoreStruct.Func1("12345");
        luaCoreStruct.Func4(luaCoreStruct);
    }
    //使用XLua提供的LuaTable映射Lua中的table
    private static void UseLuaTable()
    {
        //获取全局表LuaTable用于存储Lua中的Table
        LuaTable luaTable = XLuaSingleton.Instance.Global;
        //获取的全局变量Core,在Lua中的类型为Table对应在Xlua中的类型为LuaTable
        LuaTable luaCoreTable = luaTable.Get<LuaTable>("Core");

        //获取表中的变量依旧使用 LuaTable类型变量.Get<>();方法
        Debug.Log(luaCoreTable.Get<string>("Name"));
        //设置表中变量的值:key:变量的名称,value:为变量赋值的值
        luaCoreTable.Set<string, string>("Name", "admin");
        //获取表中的变量依旧使用 LuaTable类型变量.Get<>();方法
        Debug.Log(luaCoreTable.Get<string>("Name"));

        OneStringParams oneStringParams = luaCoreTable.Get<OneStringParams>("Func1");
        oneStringParams("admin");
        //相当于Lua中的“:”调用
        TransSelf transSelf = luaCoreTable.Get<TransSelf>("Func3");
        transSelf(luaCoreTable);
    }
    private void OnDestroy()
    {
        XLuaSingleton.Instance.Free();
    }
}
--Lua:
--C#调用Lua的Table
Core = {}--定义一个表
--向表中添加成员

Core.ID = 100
Core.Name = 'root'
Core.IsMan = 'true'

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

Core.Func2 = function()
	return "这是Core表中的Func2函数"
end
--第一种self调用写法
-- 成员函数定义时,显式加入self变量,对应C#的this关键字,表示自身对象
-- 函数内部可以通过self变量获取当前table的其他值或函数
Core.Func3 = function(self)--此时:self可以为其它名称,但是职责相同
	print("这是Core表中的Fun3函数,Core表的成员变量Name是".. self.Name)
end
--第二中Self调用方法
--隐式加入self变量  调用表中的成员需要用冒号”:“
--不能写为:
--Core:Func4=function()
--正确写法:
function Core:Func4 ()
	print("这是Core表中的Fun4函数,Core表的成员变量ID是".. self.ID)
end
-------------------------------
//最终输出结果:
UseLuaTable():
root
admin
LUA: 这是Core表中的Func1函数,接收到C#数据:admin
LUA: 这是Core表中的Fun3函数,Core表的成员变量Name是admin
UseStruct():
通过结构体存储Lua中的表中的ID:100
LUA: 这是Core表中的Func1函数,接收到C#数据:12345
LUA: 这是Core表中的Fun4函数,Core表的成员变量ID是100

一些错误与解决截图

lua的require方法导入模块时报错 unexpected symbol near ‘<\239>’:编码格式不正确,解决方法是设置文件的编码为UTF8 without BOM。

alt

alt

alt

alt

alt

alt