xLua热更新插件
一.xLua插件下载安装
1.从GitHub上搜索并下载插件

2.将文件复制到unity中


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();
} }

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();
} }

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();
} }

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();
} }

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();
}
}

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();
}
}

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
}

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版本,这里代码没有问题,但是运行始终会报错。

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();
}
}

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();
}
}

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();
}
}

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();
}
}

三.在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)最后看运行结果

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"


3.访问成员属性和方法,使用冒号语法糖
local gameObject = CS.UnityEngine.GameObject
local camera = gameObject.Find("Main Camera") --调用成员方法使用冒号语法糖(推荐),或者将自身作为第一个参数传递(不推荐)
local cameraComponent = camera:GetComponent("Camera")
gameObject.Destroy(cameraComponent)

4.其他
1)C#中的out参数映射到lua中时不算参数,C#中的out和ref返回值映射到lua中对应多返回值。
2)xlua支持方法的重载
3)支持可变参数
4)lua不支持泛型,但是可以通过Extension methods功能进行封装后使用
5)C#的委托的调用和普通方法相同,注册或者移除委托中的方法时需要将“+”或者“-”号作为第一个参数传递
xLua热更新插件的更多相关文章
- 深入理解xLua热更新原理
热更新简介 热更新是指在不需要重新编译打包游戏的情况下,在线更新游戏中的一些非核心代码和资源,比如活动运营和打补丁.热更新分为资源热更新和代码热更新两种,代码热更新实际上也是把代码当成资源的一种热更新 ...
- Unity3D|-XLua热更新用法的大致流程
xlua是由腾讯维护的一个开源项目,我们可以在github上下载这个开源项目并查看一些相关文档 官网:https://github.com/Tencent/xLua 配置文档:https://gith ...
- XLua热更新用法全流程总结(所有容易出问题的点)
Xlua热更新流程总结 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心创 ...
- Cordova - XCode10编译热更新插件错误解决方法!
操作系统:OSX10.14 XCode:10.1 热更新插件:https://github.com/nordnet/cordova-hot-code-push 这个热更新插件,在安卓下编译,没有问题, ...
- 本地服务器热更新 插件 live-server
本地服务器热更新 插件 live-server 超级好用 强烈种草一波 无需安装到项目中 使用方法如下: 1.先全局安装live-server: npm i http-server -g 2.在需要热 ...
- cordova热更新插件的使用:cordova-hot-code-push-plugin
1. 添加插件:cordova plugin add cordova-hot-code-push-plugin 2. 先打开cli,执行命令 npm install -g cordova-hot-co ...
- unity3d热更新插件uLua学习整理
前言 IOS不能热更新,不是因为不能用反射,是因为System.Reflection.Assembly.Load 无法使用System.Reflection.Emit 无法使用System.CodeD ...
- [Android教程] Cordova开发App入门(二)使用热更新插件
前言 不知各位遇没遇到过,刚刚发布的应用,突然发现了一个隐藏极深的“碧油鸡(BUG)”,肿么办!肿么办!肿么办!如果被老板发现,一定会让程序员哥哥去“吃鸡”.但是想要修复这个“碧油鸡”,就必须要重新打 ...
- [XLua]热更新四部曲视频教程+示例源码
基于Unity2017 xLua是由腾讯维护的一个开源项目,xLua为Unity. .Net. Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些Lua代码可以方便的和C#相互调用.自20 ...
随机推荐
- HotSpot学习(二):虚拟机的启动过程源码解析
1. 前言 上文介绍了HotSpot编译和调试的方法,而这篇文章将迈出正式调试的第一步--调试HotSpot的启动过程. 学习启动过程可以帮助我们了解程序的入口,并对虚拟机的运行有个整体的把握,方便日 ...
- phoenix启动报错:org.apache.phoenix.exception.PhoenixIOException: SYSTEM.CATALOG
错误: org.apache.phoenix.exception.PhoenixIOException: SYSTEM.CATALOG at org.apache.phoenix.util.Serve ...
- Let’s Encrypt 通配符证书,泛域名证书申请配置
首先你可以查看下官方提供的支持申请通配符证书的客户端列表:https://letsencrypt.org/docs/client-options/. 参考链接:https://github.com/N ...
- 服务器报错"您的主机中的软件中止了一个已建立的连接"
网上很多的说法都模棱两可,只是说和远程连接有关,这个说的太泛泛了. 我现在遇到的问题是java web出现的, 执行表单提交的时候出现该错误,原因是ajax和表单同时提交导致的, 相信很多朋友用了aj ...
- ctfshow—web—web6
打开靶机 发现登录窗,首先想到SQL注入 抓包,进行SQL注入测试 测试发现空格符被过滤了 使用/**/代替空格符进行绕过,绕过后登录成功 检测回显位 开始查询数据库名 开始查询数据库内数据表名称 查 ...
- C# url的编码解码,xml和json的序列化和反序列化
参考中国慕课网dot net web编程应用程序实践 using System; using System.Collections.Generic; using System.IO; using Sy ...
- 原生js制作表单验证,基本的表单验证方法
表单验证是web前端最常见的功能之一,也属于前端开发的基本功.自己完成一个表单验证的开发,也有助于加深对字符串处理和正则表达式的理解. 基本的表单验证包括如:字母验证.数字验证.字母和数字验证.汉字验 ...
- EnvironmentPostProcessor怎么做单元测试?阿里P7解答
简介 从Spring Boot 1.3开始,我们可以在应用程序上下文刷新之前使用EnvironmentPostProcessor来自定义应用程序的Environment.Environment表示当前 ...
- 深度解读设备的“万能语言”HarmonyOS的分布式软总线能力
摘要:本文分享鸿蒙分布式软总线,并对相关源代码进行解析,为在鸿蒙系统平台上工作的相关人员的信息参考和指导. 总线是一种内部结构,在计算机系统中,主机的各个部件通过总线相连,外部设备通过相应的接口电路再 ...
- JS实现植物大战僵尸小游戏,代码记录及效果展示
前几天看到了一个很有趣的demo,用js制作植物大战僵尸小游戏,本着学习的心态,对照着做了一下,发现这里面的一些代码设计的确很精妙,这里分享下源码和效果,如果有需要,可以看下. 效果如下: 下载地址