Unity项目接入xLua的一种流程

ops/2025/2/9 11:03:09/

lua_0">1. 导入xlua

首先导入xlua,这个不用多说
在这里插入图片描述

2. 编写C#和Lua交互脚本

基础版本,即xlua自带的版本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System;
using System.IO;[Serializable]
public class Injection
{public string name;public GameObject value;
}/// <summary>
/// XLua的原生版本
/// </summary>
public class LuaBehaviour : MonoBehaviour
{public TextAsset luaScript;public Injection[] injections;/// <summary>/// 虚拟机唯一/// </summary>internal static LuaEnv luaEnv = new LuaEnv();/// <summary>/// 上一次的GC时间/// </summary>internal static float lastGCTime = 0; /// <summary>/// GC间隔/// </summary>internal const float GCInterval = 1f;private Action luaStart;private Action luaUpdate;private Action luaOnDestroy;private LuaTable scriptScopeTable;private void Awake(){SetPackagePath();scriptScopeTable = luaEnv.NewTable();//给scriptScopeTable设置__index元表,使其能够访问全局using (LuaTable meta = luaEnv.NewTable()){meta.Set("__index", luaEnv.Global);scriptScopeTable.SetMetaTable(meta);}scriptScopeTable.Set("self", this);foreach (var injection in injections){scriptScopeTable.Set(injection.name, injection.value);}//执行脚本luaEnv.DoString(luaScript.text, luaScript.name, scriptScopeTable);//获得生命周期绑定,这里直接使用scriptScopeTable,代表是使用这个脚本的全局去设置的Action luaAwake = scriptScopeTable.Get<Action>("Awake");scriptScopeTable.Get("Start", out luaStart);scriptScopeTable.Get("Update", out luaUpdate);scriptScopeTable.Get("OnDestroy", out luaOnDestroy);if (luaAwake != null){luaAwake();}}private void Start(){if (luaStart != null){luaStart();}}private void Update(){if (luaUpdate != null){luaUpdate();}if (Time.time - lastGCTime > GCInterval){luaEnv.Tick();lastGCTime = Time.time;}}private void OnDestroy(){if (luaOnDestroy != null){luaOnDestroy();}scriptScopeTable.Dispose();luaStart = null;luaUpdate = null;luaOnDestroy = null;injections = null;}/// <summary>/// 设置xlua的加载路径/// </summary>private void SetPackagePath(){//在Unity项目的“Assets”文件夹(或指定的Application.dataPath路径)及其所有子目录中,查找名为“LuaScripts”的目录,并返回一个包含这些目录路径的字符串数组foreach (string dir in Directory.GetDirectories(Application.dataPath,"LuaScripts", SearchOption.AllDirectories)){luaEnv.AddLoader(new FileLoader(dir, ".lua"));luaEnv.AddLoader(new FileLoader(dir, ".lua.txt"));}}
}

Loxodon的版本

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System.IO;
using Object = UnityEngine.Object;/// <summary>
/// Loxodon的版本
/// </summary>
[LuaCallCSharp]
public class LoxodonLuaBehaviour : MonoBehaviour
{public ScriptReference script;public VariableArray variables;protected LuaTable scriptEnv;protected LuaTable metatable;protected Action<MonoBehaviour> onAwake;protected Action<MonoBehaviour> onEnable;protected Action<MonoBehaviour> onDisable;protected Action<MonoBehaviour> onUpdate;protected Action<MonoBehaviour> onDestroy;protected Action<MonoBehaviour> onStart;public LuaTable GetMetatable(){return metatable;}protected virtual void Initialize(){var luaEnv = LuaEnvironment.LuaEnv;scriptEnv = luaEnv.NewTable();LuaTable meta = luaEnv.NewTable();meta.Set("__index", luaEnv.Global);scriptEnv.SetMetaTable(meta);meta.Dispose();scriptEnv.Set("target", this);SetPackagePath(luaEnv);string scriptText = (script.Type == ScriptReferenceType.TextAsset)? script.Text.text: string.Format($"require(\"System\");local cls = require(\"{script.FileName}\");return extends(target,cls);");object[] result = luaEnv.DoString(scriptText, string.Format("{0}({1})", "LuaBehaviour", this.name), scriptEnv);if (result.Length != 1 || !(result[0] is LuaTable)){throw new Exception("");}metatable = (LuaTable)result[0];  //这里使用Lua脚本的返回值去设置,即脚本的返回值去绑定生命周期if (variables != null && variables.Variables != null){foreach (var variable in variables.Variables){var name = variable.Name.Trim();if (string.IsNullOrEmpty(name)){continue;}metatable.Set(name, variable.GetValue());}}onAwake = metatable.Get<Action<MonoBehaviour>>("Awake");onEnable = metatable.Get<Action<MonoBehaviour>>("Enable");onDisable = metatable.Get<Action<MonoBehaviour>>("Disable");onStart = metatable.Get<Action<MonoBehaviour>>("Start");onUpdate = metatable.Get<Action<MonoBehaviour>>("Update");onDestroy = metatable.Get<Action<MonoBehaviour>>("Destroy");}protected virtual void Awake(){this.Initialize();if (this.onAwake != null){this.onAwake(this);}}protected virtual void OnEnable(){if (this.onEnable != null){this.onEnable(this);}}protected virtual void OnDisable(){if (this.onDisable != null){this.onDisable(this);}}protected virtual void Start(){if (onStart != null){onStart(this);}}protected virtual void Update(){if (onUpdate != null){onUpdate(this);}}protected virtual void OnDestroy(){if (this.onDestroy != null){this.onDestroy(this);}onDestroy = null;onUpdate = null;onStart = null;onEnable = null;onDisable = null;onAwake = null;if (metatable != null){metatable.Dispose();metatable = null;}if (scriptEnv != null){scriptEnv.Dispose();scriptEnv = null;}}/// <summary>/// 修改lua的loader/// </summary>/// <param name="luaEnv"></param>private void SetPackagePath(LuaEnv luaEnv){//在Unity项目的“Assets”文件夹(或指定的Application.dataPath路径)及其所有子目录中,查找名为“LuaScripts”的目录,并返回一个包含这些目录路径的字符串数组foreach (string dir in Directory.GetDirectories(Application.dataPath,"LuaScripts", SearchOption.AllDirectories)){luaEnv.AddLoader(new FileLoader(dir, ".lua"));luaEnv.AddLoader(new FileLoader(dir, ".lua.txt"));}}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;public class LuaEnvironment
{private static float interval = 2;private static WaitForSecondsRealtime wait;private static LuaEnv luaEnv;//private static IAsyncResult result;public static float Interval{get => interval;set{if (interval <= 0){return;}interval = value;wait = new WaitForSecondsRealtime(interval);}}public static LuaEnv LuaEnv{get{if (luaEnv == null){luaEnv = new LuaEnv();// if (result != null)//     result.Cancel();wait = new WaitForSecondsRealtime(interval);//result = Executors.RunOnCoroutine(DoTick());luaEnv.Tick();}return luaEnv;}}public static void Dispose(){// if (result != null)// {//     result.Cancel();//     result = null;// }if (luaEnv != null){luaEnv.Dispose();luaEnv = null;}wait = null;}private static IEnumerator DoTick(){while (true){yield return wait;try{luaEnv.Tick();}catch (Exception e){Debug.LogError(e);}}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Object = UnityEngine.Object;public enum ScriptReferenceType
{TextAsset,FileName
}[Serializable]
public class ScriptReference : ISerializationCallbackReceiver
{
#if UNITY_EDITOR[SerializeField]private Object cachedAsset;
#endif[SerializeField]protected TextAsset text;[SerializeField]protected string fileName;[SerializeField]protected ScriptReferenceType type = ScriptReferenceType.TextAsset;public virtual ScriptReferenceType Type => type;public virtual TextAsset Text => text;public virtual string FileName => fileName;public void OnBeforeSerialize(){Clear();}public void OnAfterDeserialize(){Clear();}protected virtual void Clear(){
#if !UNITY_EDITORswitch (type){case ScriptReferenceType.TextAsset:this.fileName = null;break;case ScriptReferenceType.FileName:this.text = null;break;}
#endif}
}

具体区别可以看两种不同的LuaBehaviour生命周期绑定

然后注意这里的lua文件读取路径设置
在这里插入图片描述
具体可以看xlua中自定义lua文件加载的一种方式
在这里插入图片描述

3.自定义属性面板

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. Lua脚本部分

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

因为提前设置了Lua文件的读取路径,都在LuaScripts文件夹下

运行
在这里插入图片描述

在这里插入图片描述
Lua脚本执行了对应的逻辑,将text的值变为了“你好”,同时打印了协程的输出

注意使用前让xlua生成代码
在这里插入图片描述

项目链接


http://www.ppmy.cn/ops/156953.html

相关文章

VSCode 换行符问题

换行符格式 在 Visual Studio Code (VSCode) 中&#xff0c;换行符问题通常涉及两种常见的换行符格式&#xff1a;CRLF&#xff08;Carriage Return Line Feed&#xff09;和 LF&#xff08;Line Feed&#xff09;。 默认情况下&#xff0c;VSCode 在不同操作系统上使用适当的…

hot100(9)

81.104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 后序遍历&#xff0c;从下往上&#xff0c;需要用到下面返回的结果。 public int maxDepth(TreeNode root) {if(root null){return 0;}int left maxDepth(root.left);int right maxDepth(root.right);re…

优惠券平台(十三):基于注解和Spring AOP环绕通知实现去重表消息防止重复消费

业务背景 考虑这样两个场景&#xff1a; 消息 M 被发送到消息中间件并被消费者 A 接收&#xff0c;但在消费过程中系统重启&#xff0c;由于消息未被标记为成功消费&#xff0c;中间件会重复投递&#xff0c;直到消费成功&#xff0c;但可能导致消息被多次投递。 消费者 A 在…

解决错误:CondaHTTPError: HTTP 000 CONNECTION FAILED for url

解决错误&#xff1a;CondaHTTPError: HTTP 000 CONNECTION FAILED for url 查看channels:vim ~/.condarcshow_channel_urls: true channels:- http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/- http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/…

Docker最佳实践:安装Nacos

文章目录 Docker最佳实践&#xff1a;安装Nacos一、引言二、安装 Nacos1、拉取 Nacos Docker 镜像2、启动 Nacos 容器 三、配置 Nacos&#xff08;可选&#xff09;四、使用示例1、服务注册2、服务发现 五、总结 Docker最佳实践&#xff1a;安装Nacos 一、引言 Nacos 是阿里巴…

腾讯云TI平台×DeepSeek:开启AI超强体验,解锁部署秘籍

引言 在人工智能飞速发展的今天&#xff0c;AI技术的应用场景已经渗透到我们生活的方方面面。从智能客服到自动驾驶&#xff0c;从精准医疗到金融科技&#xff0c;AI的应用正在不断推动各行业的变革与创新。作为AI领域的领军企业&#xff0c;腾讯云一直以来都在致力于为开发者…

.net framework 4.5 的项目,用Mono 部署在linux

步骤 1&#xff1a;安装 Mono 更新包列表&#xff1a; 首先&#xff0c;更新 Ubuntu 的包列表以确保获取最新的软件包信息。 sudo apt update 安装 Mono&#xff1a; 安装 Mono 完整版&#xff08;mono-complete&#xff09;&#xff0c;它包含了运行 .NET 应用程序所需的所有…

redis中的list类型

可以看作一个双向链表结构&#xff0c;支持正向和反向检索&#xff0c;有序&#xff0c;元素可以重复&#xff0c;插入和删除快&#xff0c;查询速度一般 list类型常见命令&#xff1a; LPUSH key element... : 向链表左侧插入一个或多个元素 LPOP key&#xff1a;移除并返回…