Unity项目接入xLua的一种流程

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_EDITOR
        switch (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生成代码
在这里插入图片描述

项目链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/967004.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LM Studio 部署本地大语言模型

一、下载安装 1.搜索&#xff1a;lm studio LM Studio - Discover, download, and run local LLMs 2.下载 3.安装 4.更改成中文 二、下载模型(软件内下载) 1.选择使用代理&#xff0c;否则无法下载 2.更改模型下载目录 默认下载位置 C:\Users\用户名\.lmstudio\models 3.搜…

route 与 router 之间的差别

简述&#xff1a; router&#xff1a;主要用于处理一些动作&#xff0c; route&#xff1a;主要获得或处理一些数据&#xff0c;比如地址、参数等 例&#xff1a; videoInfo1.vue&#xff1a; <template><div class"video-info"><h3>二级组件…

DeepSeek-V2 论文解读:混合专家架构的新突破

论文链接&#xff1a;DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model 目录 一、引言二、模型架构&#xff08;一&#xff09;多头部潜在注意力&#xff08;MLA&#xff09;&#xff1a;重塑推理效率&#xff08;二&#xff09;DeepSeekM…

Android修行手册-五种比较图片相似或相同

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材…

力扣--链表

相交链表 法一&#xff1a; 把A链表的节点都存HashSet里&#xff0c;遍历B链表找相同的节点 法二&#xff1a; 把A、B指针都移到末尾&#xff0c;再同时往回走&#xff0c;每次往回走都比较 当前节点的下一节点&#xff08;a.next b.next ?)是否相同&#xff0c;当不相同…

只需两步,使用ollama即可在本地部署DeepSeek等常见的AI大模型

只需两步&#xff0c;使用ollama即可在本地部署DeepSeek等常见的AI大模型 1.下载ollama,进入ollama官网即可将ollama下载到本地&#xff0c;之后按照提示安装ollama。 https://ollama.com/download/windows 2.安装大模型 进入ollama官网模型页面&#xff0c;找到所需的模型及版…

Qt修仙之路2-1 仿QQ登入 法宝初成

widget.cpp #include "widget.h" #include<QDebug> //实现槽函数 void Widget::login1() {QString userusername_input->text();QString passpassword_input->text();//如果不勾选无法登入if(!check->isChecked()){qDebug()<<"xxx"&…

大模型deepseek-r1 本地Open WebUI部署详解

一、Open WebUI简介 Open WebUI是一个用户友好的Web界面&#xff0c;专为本地大语言模型&#xff08;LLMs&#xff09;设计。它支持多种模型&#xff0c;包括Ollama和OpenAI兼容的API&#xff0c;并允许用户通过图形界面轻松调试和调用模型。Open WebUI的功能丰富&#xff0c;…

免费windows pdf编辑工具Epdf

Epdf&#xff08;完全免费&#xff09; 作者&#xff1a;不染心 时间&#xff1a;2025/2/6 Github: https://github.com/dog-tired/Epdf Epdf Epdf 是一款使用 Rust 编写的 PDF 编辑器&#xff0c;目前仍在开发中。它提供了一系列实用的命令行选项&#xff0c;方便用户对 PDF …

大模型训练(7):集合通信与通信原语

0 背景 分布式训练过程中设计到许多通信上的操作&#xff0c; 每个操作有其不同的术语并且有所区别&#xff0c;这里将其用简单的例子和描述总结一下&#xff0c;方便理解。 集合通信&#xff08;Collective Communications&#xff09;是一个进程组的所有进程都参与的全局通…

线程上下文-ThreadLocal原理

ThreadLocal主要作用&#xff1a;为每个线程提供独立的变量副本&#xff0c;实现线程间的数据隔离&#xff0c;从而避免多线程环境下的资源共享冲突。 原理 ThreadLocal有个内部类 ThreadLocalMap&#xff0c;顾名思义是个Map结构&#xff1a;key为 ThreadLocal实例&#xff0…

第31周:文献阅读

目录 摘要 Abstract 文献阅读 问题引入 研究背景 研究动机 创新点 动态预训练方法&#xff08;DynPT&#xff09; 深度循环神经网络&#xff08;DRNN&#xff09; 传感器选择 方法论 时间序列的动态预训练 异构传感器数据的DRNN 基于稀疏度的传感器过滤 实验研…

Yolo图片标注的一些问题

1.标注工具的选择 在img.net和瑞芯微的双重加持下&#xff0c;现在的计算机视觉识别已经在各行业快速推进。进行自行标注时&#xff0c;首先遇到的问题就是标注工具的选择问题&#xff0c;标注工具不需要自己手工完成——也没有必要。类似这样的通用需求&#xff0c;交给专业…

排错 -- 用React.js,Solidity,智能合约构建最新区块链应用

真枪实弹:第一个Web3项目【上集】用React.js,Solidity,智能合约构建最新区块链应用详细教程 构建web跟随b站教程中遇到了很多错误&#xff0c;从今天开始构建完整的应用&#xff0c;在此记录一些排错。 问题情况1&#xff1a;跟随视频后无Src文件 问题情况1解决方法&#xff1…

杂记:下载了BootLoader和APP到程序中无反应

杂记&#xff1a;下载了BootLoader和APP到程序中无反应 是因为采用了printf输出打印。占用了大量堆栈导致程序运行异常。并且没有打开Use MicroLIB库的话会导致无法启动程序。 解决办法&#xff1a; 1、关闭printf打印。 2、如果不关闭printf打印&#xff0c;则加大Heap_Size…

Unet 改进:引入残差模块ResidualBlock

目录 1. ResidualBlock 2. UNet 引入残差模块 Tips:融入模块后的网络经过测试,可以直接使用,设置好输入和输出的图片维度即可 1. ResidualBlock 残差连接(Residual Connection)是深度学习中一种重要的技术,主要用于解决深层网络训练中的梯度消失和网络退化问题。它首次…

对接DeepSeek

其实&#xff0c;整个对接过程很简单&#xff0c;就四步&#xff0c;获取key&#xff0c;找到接口文档&#xff0c;接口测试&#xff0c;代码对接。 获取 KEY https://platform.deepseek.com/transactions 直接付款就是了&#xff08;现在官网暂停充值2025年2月7日&#xff0…

【基于SprintBoot+Mybatis+Mysql】电脑商城项目之上传头像和新增收货地址

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【Spring篇】【计算机网络】【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f680;1.上传头像 -持久…

【大模型】硅基流动对接DeepSeek使用详解

目录 一、前言 二、硅基流动介绍 2.1 硅基流动平台介绍 2.1.1 平台是做什么的 2.2 主要特点与功能 2.2.1 适用场景 三、硅基流动快速使用 3.1 账户注册 3.2 token获取 3.2.1 获取token技巧 四、Cherry-Studio对接DeepSeek 4.1 获取 Cherry-Studio 4.2 Cherry-Stud…

告别2023~2024

时间过得真快&#xff0c;距离上次写作2年多了。2023年&#xff5e;2024年的这两年时光里经历太多人生大事&#xff1a; 房贷&#xff0c;提前还贷买车&#xff0c;全款拿下租房搬家媳妇怀孕&#xff0c;独自照顾&#xff0c;……老人离世开盲盒喜提千金&#xff0c;百岁宴&am…