首页 > 其他分享 >XLua基础

XLua基础

时间:2022-09-20 18:02:00浏览次数:82  
标签:name C# 基础 XLua lua int env print

一、认识XLua

Xlua是一个插件,用于实现C#和lua语言的交互。
为什么要学习XLua?
通常我们使用XLua方案实现热更新,也就是基于Xlua插件来实现热更新方案。像这样类似功能的插件还有ulua、tolua等等。
热更新就是:当我们增加新功能,我们不需要重新安装下载安装包,就可以更新游戏内容

为什么使用Lua语言?
lua:跨平台、不需要编译(解释型语言),直接生成安装包。因此使用它,避免了编译的开销。

二、XLua实践

1、运行在C#环境lua代码

    private LuaEnv luaenv;
    private void Start()
    {
        luaenv = new LuaEnv();//创建lua运行环境

        luaenv.DoString("print('Hello World')");//运行lua程序
        luaenv.DoString("CS.UnityEngine.Debug.Log('Hello World')");//lua调用C#方法
    }

会直接打印到unity控制台中,与Debug.Log不同的是有一个Lua前缀

git上的官方快速入门有这样一条建议
一个LuaEnv实例对应Lua虚拟机,出于开销的考虑,建议全局唯一。

在实际环境中通常是需要加载lua程序载入到unity中进行使用,而不像上面那样将代码直接写在编辑器中
我们可以先用Resources加载lua文件,读取里面的代码并使用

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

        //1、使用Resource的方式加载lua文件
        TextAsset ta = Resources.Load<TextAsset>("002/helloworld.lua");
        env.DoString(ta.text);
        //2、使用require的方式进行加载
        env.DoString("require '002/helloworld'");
        env.Dispose();
    }

我们也可以通过自定义loader的方式,来扩展require的功能。比如默认require的加载路径是在Resources文件夹之下,我们可以通过自定义的方式进行修改

    void Start()
    {
        LuaEnv env = new LuaEnv();
        env.AddLoader(CusLoader);
        env.DoString("require 'test007'");
        env.Dispose();
    }

    private byte[] CusLoader(ref string filePath)
    {
        print(filePath);
        //string s = "print(123)";
        print(Application.streamingAssetsPath);

        string absPath = Application.streamingAssetsPath + "/" + filePath + ".lua.txt";
        return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(absPath)); //需要返回字节形式
    }

2、C#访问lua

获取lua中定义的全局变量

int age=env.Global.Get<int>("age");//获取到lua中的全局变量age
string name=env.Global.Get<string>("name");//获取到lua中的全局变量name

建立映射
lua中的代码如下:

age=100
name="baga"

person={
	name="lzy",
	age=100
}

(1)建立lua中table到C#中类和Struct的映射
先定义一个类,类名和lua中table的key值对应上

public class Person
{
    public string name;
    public int age;
}
//1、表到类的映射
        Person p = env.Global.Get<Person>("person");

值得注意的是,这种方式建立的映射实际上是一种值传递,相当于通过lua中的值来new一个新的类
想要获得引用,就需要通过下面这种方式建立映射
(2)建立lua中的table和C#中Interface的映射

[CSharpCallLua] //一定要加上这个特性
public interface IPerson
{
    string name { get; set; }
    int age { get; set; }
}

此时仅仅修改IPerson对象的值,也可以一并修改lua中全局表结构的值

//2、表到接口的映射
IPerson p = env.Global.Get<IPerson>("person");
p.name = "???";
env.DoString("print(person.name)");
print(p.age);
print(p.name);

高版本的unity可能还会发生报错,可通过以下方式解决
https://www.jianshu.com/p/0849b9a46cbd

也可以通过这两种方式映射内部函数

person={
	name="lzy",
	age=100,
	eat=function()
		print("吃个饭")
	end
}

--[
function person:pay(money,count) --不用多写一个self参数
	print(money*count)
end
--]

function person.pay(self,money,count) --需要多写一个self参数
	print(money*count)
end

映射到C#中的接口结构如下

public interface IPerson
{
    string name { get; set; }
    int age { get; set; }
    public void eat();
    public void pay(int money,int count);
}

调用函数方法

p.eat();
p.pay(2, 5);

另外,还可以使用luaTable的方式来建立映射,缺点就是性能慢

(3)将表映射到Dictionary和List下

        //表到Dictionary、List的映射
        Dictionary<string, object> dict = env.Global.Get<Dictionary<string, object>>("person");
        foreach (string key in dict.Keys)
        {
            print(key + "-" + dict[key]);
        }

        //List只能映射对应类型的值数据
        List<object> list = env.Global.Get<List<object>>("num");
        foreach(object o in list)
        {
            print(o);
        }
person={
	name="lzy",
	age=100,
	eat=function()
		print("吃个饭")
	end,
}
num={
	1,2,0.5,1.55,true,false
}

调用全局函数的方法
利用委托来接收lua中的全局函数
lua

function Hello()
	print("Hello")
	return 0,1 --lua可以有多个返回值
end

C#

[CSharpCallLua]
    delegate int Hello(out int resa,out int resb);
        //4、访问全局函数
        Hello action = env.Global.Get<Hello>("Hello");
        int resa;
        int resb;
        int res=action(out resa, out resb);//报错是因为Action有引用 使用out来接收多个返回值
        action = null; //释放delegate
        print(res);
        print(resa);
        print(resb);

有一个报错,就是当释放delegage和env.Dispose放在同一个方法内时会出错。
https://www.codenong.com/js58d20d46560a/
还可以使用luaFunction的方式,但是性能较慢

3、lua访问C#

(1)lua访问C#的静态属性和方法、成员属性等
lua:

--构造游戏物体,new 对象
--CS.UnityEngine.GameObject()

--访问静态属性和方法
local GameObject=CS.UnityEngine.GameObject
print(CS.UnityEngine.Time.deltaTime)
camera=GameObject.Find("Main Camera")
print(camera.name)

--访问成员属性和方法
camTrans=camera:GetComponent("Transform")--使用:可以不用将成员作为第一个参数传入
print(camTrans.position)

C#

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

        env.DoString("require '005/LuaCallCSharp'");

        env.Dispose();
    }

(2)其他类型
Lua也同样支持C#的访问父类、重载、可变参数、枚举、委托、事件等等
略...参考Xlua中的Xlua教程

三、XLua热更新方案

先前介绍了,就是使用lua代码来操作unity中的组件和各种游戏物体,利用lua来开发unity的功能。那么热更新是如何实现的?

要更新的有两部分:资源(打包成了Assetbundle) and 代码
AssetBundle和lua代码放到了服务端,当玩家连接到服务器,检查AssetBundle和Lua代码更新,如需要更新就把新内容下载到本地。
此外使用MD5校验,可以检查哪些内容需要更新。

标签:name,C#,基础,XLua,lua,int,env,print
From: https://www.cnblogs.com/fjnloo/p/16708483.html

相关文章

  • 前端基础知识-css(一)个人学习记录
    待补充flex及其属性https://blog.csdn.net/weixin_44706267/article/details/121291934css3新特性sass和lesshttps://www.cnblogs.com/dasusu/p/10114097.html......
  • Java基础之ClassFile文件结构
    本文相关知识均来自:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html.class文件都遵循ClassFile结构:ClassFile{u4magic;u2......
  • 【Java基础】System.out.println() 解析
    1.代码说明System类提供一些有用的属性和方法,包括标准输入输出和错误打印。有一个对象属性out,类型为PrintStream。setOut()方法使用static修饰,类加载时执行。该对象属......
  • Docker基础知识 (12) - 使用 Docker-compose 部署 Nginx + Php/Laravel + MariaDB 项
    Laravel是一套简洁、优雅的PHPWeb开发框架(PHPWebFramework)。Laravel:https://laravel.com/LaravelGitHub:https://github.com/laravel1.部署环境   IP......
  • JAVA入门基础_从零开始的培训_Redis
    目录Redis能够为我们解决什么问题Redis的下载与安装前台启动(不推荐)与后台启动常用五大数据类型Redis键常用命令(key)4个数据库操作命令String字符串命令String的内存结构Li......
  • JAVA SE 基础总结
    §基础知识一、程序组织与运行原理1.1程序组织一个JAVA程序文件中主要由如下几部分构成:package声明public类:public类与类文件名相同,因为其是作为该类文件......
  • HDFS基础命令
    列出文件目录hdfsdfs-ls/user/hive/warehouse列出全部目录与文件hdfsdfs-ls-R/user/hive/warehouse查看目录文件大小hdfsdfs-du-s-h/user/hive/wa......
  • 【Java基础】代码块
    1.代码块说明一对花括号表示,仅可以使用static修饰,可以用来对类或对象进行初始化。静态代码块:static修饰随着类的加载而执行,只执行一次,有多个时,按顺序执行。无法调用......
  • 浅谈Flexray基础通讯测试
      随着车载网络发展,ECU的通讯速率相较以往得到飞速提升。现今多数OEM在中高速通讯场景中仍采用CANFD进行过渡,但当同时考虑安全和更高带宽要求时,CANFD则无法满足,FlexRay则......
  • python-接口自动化测试-基础知识(一)
    Python接口自动化测试理论知识以及框架源码一、什么是接口测试、为什么要做接口测试1、什么是接口测试接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测......