xLua热更新插件

一.xLua插件下载安装

1.从GitHub上搜索并下载插件

xLua热更新插件

 

 2.将文件复制到unity中

xLua热更新插件

 

 xLua热更新插件

 

 3.检查是否有错误

二.在unity中调用lua

1.简单调用

在c#脚本中使用LuaEnv类可以运行lua,建议LuaEnv实例全局唯一。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//引入命名空间
using XLua;

public class HelloLua01 : MonoBehaviour
{
    //声明luaenv变量
    private LuaEnv luaenv;

    void Start()
    {
        //实例化luaenv变量
        luaenv = new LuaEnv();
        //调用DoString方法执行lua代码
        luaenv.DoString("print('hello world!')");
    }

    private void OnDestroy()
    {
        //释放luaenv
        luaenv.Dispose();
    }

}

xLua热更新插件

 

 

 2.lua文件的读取执行

using UnityEngine;
//引入命名空间
using XLua;

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        //将lua代码文件放在Resources文件夹下,并添加后缀.txt
        //通过Resources.Load方法读取这个文件,声明类型为TextAsset,这样读取的过程中就会自动添加后缀.txt
        //读取到文件的内容后转化为byte数组(使用tostring方法或者text方法转化为字符串或文本也都可以),并交给DoString方法执行这段代码
        luaenv.DoString(Resources.Load<TextAsset>("helloLua.lua").bytes);
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }

}

xLua热更新插件

using UnityEngine;
//引入命名空间
using XLua;

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        //使用系统内置的方法加载文件并执行代码,文件名是helloLua.lua.txt
        luaenv.DoString("require 'helloLua'");
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }

}

xLua热更新插件

 

 

 3.自定义Loader:针对文件后缀不是.lua.txt的类型

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();

        //通过AddLoader方法自定义Loader程序,实际上是将自定义的Loader方法添加到一个委托中
        luaenv.AddLoader(MyLoader);
        //执行DoString方法,会首先调用自定义的Loader方法,如果返回值为空,再调用系统定义的Loader方法
        luaenv.DoString("require 'helloLua'");
    }

    //自定义的Loader方法,这个方法返回值必须是byte数组,参数是ref的string类型,传入文件地址
    private byte[] MyLoader(ref string filePath)
    {
        print(filePath);
        return null;
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }

}

xLua热更新插件

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();

        luaenv.AddLoader(MyLoader);
        luaenv.DoString("require 'helloLua'");
    }

    private byte[] MyLoader(ref string filePath)
    {
        //打印文字说明这个loader函数被调用
        print("调用了自定义的loader");
        //将lua文件放入streaMingAssetsPath文件夹内,拼接好文件的完整绝对路径
        string path = Application.streamingAssetsPath + "/" + filePath + ".lua.txt";
        //读取文件,获得byte数组并返回
        return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }
}

xLua热更新插件

 

 

 4.访问lua中的变量

1)访问值类型变量

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString("require 'helloLua'");

        //访问文件中的全局int类型变量a
        print(luaenv.Global.Get<int>("a"));
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }
}

xLua热更新插件

2)访问table形式的变量,可以定义一个对应table的类进行,Get方法会自动new出这个类,并将变量值拷贝进去。

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString("require 'helloLua'");

        //获取表person的内容,存储为Person类
        Person p = luaenv.Global.Get<Person>("person");
        print(p.name + p.age);
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }

    //定义一个和表对应好属性和方法的类
    class Person
    {
        public string name;
        public int age;
    }
}
person = {
 name = 'movin',age = 18
}

xLua热更新插件

 3)也可以定义一个对应table属性和方法的接口,但是接口需要加上[CSharpCallLua]特性,同时lua中定义函数时第一个参数必须是self或者使用冒号定义

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString("require 'helloLua'");
        
        IPerson p = luaenv.Global.Get<IPerson>("person");
        print(p.name + p.age);
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }

    //如果使用接口定义接收的table,必须加上[CSharpCallLua]特性自动生成代码
    [CSharpCallLua]
    interface IPerson
    {
        string name { get; set; }
        int age { get; set; }
    }
}

这里注意:目前xlua没有支持unity2019版本,这里代码没有问题,但是运行始终会报错。

xLua热更新插件

 

 4)使用字典或者链表对应table

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString("require 'helloLua'");

        //将table转化为字典
        Dictionary<string,object> dict = luaenv.Global.Get<Dictionary<string, object>>("person");
        //遍历输出
        foreach(KeyValuePair<string,object> pair in dict)
        {
            print(pair.Key + pair.Value);
        }
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }
}

xLua热更新插件

 

 5)使用列表对应table,只能存储table中没有键的value值

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString("require 'helloLua'");

        //将table转化为list,list只能储存没有键的table值
        List<object> list = luaenv.Global.Get<List<object>>("person");
        //遍历输出
        foreach(Object o in list)
        {
            print(o);
        }
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }
}

6)使用LuaTable类对应table

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString("require 'helloLua'");

        //将table存储为luatable类的对象
        LuaTable tab = luaenv.Global.Get<LuaTable>("person");
        //取得其中的键对应的值,需要声明值类型
        print(tab.Get<string>("name"));
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }
}

xLua热更新插件

 

 7)使用委托对应lua中的函数

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString("require 'helloLua'");

        //使用委托存储lua中的函数,函数名称为add
        Add add = luaenv.Global.Get<Add>("add");
        add(1,3);
    }

    //自定义一个委托对应lua中相应的函数,一定要加上[CSharpCallLua]特性
    [CSharpCallLua]
    delegate void Add(int a, int b);
    private void OnDestroy()
    {
        luaenv.Dispose();
    }
}

xLua热更新插件

 

 2019版本的unity和xlua不兼容,使用更低版本解决问题。

如果lua有不止一个返回值,可以使用out参数或ref参数接收其他的返回值。

8)使用LuaFunction对应lua中的函数

public class HelloLua : MonoBehaviour
{
    private LuaEnv luaenv;

    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString("require 'helloLua'");

        //xlua提供了LuaFunction对应lua中的函数,使用Call方法调用函数,返回值为一个objec类型的数组
        LuaFunction func = luaenv.Global.Get<LuaFunction>("add");
        object[] objs = func.Call(1, 3);
        foreach(object o in objs)
        {
            print(o.ToString());
        }
    }

    private void OnDestroy()
    {
        luaenv.Dispose();
    }
}

xLua热更新插件

 

 三.在lua中调用C#

1.简单实现调用

1)首先在空物体上挂载脚本,脚本调用lua代码

public class LuaCallCSharp : MonoBehaviour
{
    private LuaEnv luaEnv;

    void Start()
    {
        luaEnv = new LuaEnv();

        luaEnv.DoString("require 'LuaCallCSharp'");
    }

    private void OnDestroy()
    {
        luaEnv.Dispose();
    }
}

2)然后在lua代码中实例化一个游戏物体

--创建游戏物体,对应C#中的new UnityEngine.GameObject()代码
CS.UnityEngine.GameObject()

3)最后看运行结果

xLua热更新插件

 

 4)注意事项:lua中没有new关键字,所有C#相关的内容都放在了CS下,包括函数、属性和方法等。对于经常访问的类,可以先使用局部变量存储起来,然后再进行调用,减少代码量也提高性能。

2.访问静态属性和方法

--对应的C#代码:print(UnityEngine.Time.deltaTime);
print(CS.UnityEngine.Time.deltaTime)

--对应的C#代码:UnityEngine.GameObject.Find("Main Camera").name = "fixed by lua"
CS.UnityEngine.GameObject.Find("Main Camera").name = "fixed by lua"

xLua热更新插件xLua热更新插件

 

 3.访问成员属性和方法,使用冒号语法糖

local gameObject = CS.UnityEngine.GameObject
local camera = gameObject.Find("Main Camera")

--调用成员方法使用冒号语法糖(推荐),或者将自身作为第一个参数传递(不推荐)
local cameraComponent = camera:GetComponent("Camera")
gameObject.Destroy(cameraComponent)

xLua热更新插件

4.其他

1)C#中的out参数映射到lua中时不算参数,C#中的out和ref返回值映射到lua中对应多返回值。

2)xlua支持方法的重载

3)支持可变参数

4)lua不支持泛型,但是可以通过Extension methods功能进行封装后使用

5)C#的委托的调用和普通方法相同,注册或者移除委托中的方法时需要将“+”或者“-”号作为第一个参数传递

上一篇:记一次xlua热更问题


下一篇:git忽略本地提交命令