zoukankan      html  css  js  c++  java
  • Unity热更新--XLua的简单封装

      刚开始看XLua热更部分,主要不是为了项目热更的需求,而是为了自己调试方便。

    每次发布Webgl都要打包好久,所以直接搞了个XLua环境,只打一次包,剩下都在StreamingAssets里面修改lua代码即可。

    核心功能:

        LuaTable luaTable = luaEnv.NewTable();
        LuaTable tempLuaTb = luaEnv.NewTable();
        tempLuaTb.Set("__index", luaEnv.Global);
        luaTable.SetMetaTable(tempLuaTb);
        tempLuaTb.Dispose();
        luaTable.Set("self", obj);
        if (injections != null && injections.Length > 0)
        {
            for (int i = 0; i < injections.Length; i++)
            {
                 luaTable.Set(injections[i].key, injections[i].value);
            }
        }
        luaEvnItem = new LuaEvnItem(fileName, new List<string>() { funcName }, "", injections, luaTable, tempLuaTb);
        luaEvnItems.Add(luaEvnItem);            

    为每个脚本生成独立的LuaTable,

    之后再获取到对应的LuaTable进行

    LuaEvn.DoString(将要执行的lua脚本文本我这里传入的是脚本名LuaTable

    就行了。

    Injection里面存放key和value,

    key对应lua里面使用的变量,value对应场景中的GameObject变量,

    这样注入就省去在Lua中获取了。

    luaTable.Set("self", obj); 这句将当前的脚本对象赋值给self。在lua中可以直接调用self.xxxx

    完整代码:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using XLua;
    
    
    public class LuaManager : MonoBehaviour
    {
        static LuaManager instance;
    
        public static LuaManager Instance
        {
            get
            {
                if (instance == null)
                {
                    GameObject go = GameObject.Find("Single_"+typeof(LuaManager).ToString());
                    if (go != null)
                    {
                        instance = go.GetComponent<LuaManager>();
    
                    }
                    else
                    {
                        go = new GameObject("Single_" + typeof(LuaManager).ToString());
                        instance = go.AddComponent<LuaManager>();
                    }
                }
                return instance;
            }
        }
    
        public static LuaEnv luaEnv = new LuaEnv();
    
        List<LuaEvnItem> luaEvnItems = new List<LuaEvnItem>();
    
        public Action<string, string, Action<object[]>> ToDoAction;
    
        public void WriteByLua<T>(T obj, string fileName, string funcName, Injection[] injections = null)
        {
            Action<object[]> InvokeActtion = null;
            LuaEvnItem luaEvnItem = luaEvnItems.Find((tempItem) => { return tempItem.fileName == fileName; });
            if (luaEvnItem == null)
            {
                LuaTable luaTable = luaEnv.NewTable();
                LuaTable tempLuaTb = luaEnv.NewTable();
                tempLuaTb.Set("__index", luaEnv.Global);
                luaTable.SetMetaTable(tempLuaTb);
                tempLuaTb.Dispose();
                luaTable.Set("self", obj);
                if (injections != null && injections.Length > 0)
                {
                    for (int i = 0; i < injections.Length; i++)
                    {
                        luaTable.Set(injections[i].key, injections[i].value);
                    }
                }
                luaEvnItem = new LuaEvnItem(fileName, new List<string>() { funcName }, "", injections, luaTable, tempLuaTb);
                luaEvnItems.Add(luaEvnItem);
            }
            string path = "";
            if (Application.platform == RuntimePlatform.WebGLPlayer && Application.platform != RuntimePlatform.WindowsEditor)
            {
                path = "./StreamingAssets/LuaScripts/" + fileName + ".lua";
            }
            else
            {
                path = Application.streamingAssetsPath + "/LuaScripts/" + fileName + ".lua";
            }
    
            string downloadInfo = System.IO.File.ReadAllText(path);
    
            if (!string.IsNullOrEmpty(downloadInfo))
            {
                luaEnv.DoString(downloadInfo, luaEvnItem.fileName, luaEvnItem.luaTable);
            }
            else
            {
                luaEnv.DoString(Resources.Load<TextAsset>(luaEvnItem.fileName).text, luaEvnItem.fileName, luaEvnItem.luaTable);
            }
            luaEvnItem.luaData = downloadInfo;
            luaEvnItem.luaTable.Get(funcName, out InvokeActtion);
            if (ToDoAction != null)
            {
                ToDoAction(luaEvnItem.fileName, funcName, InvokeActtion);
            }
        }
    }
    
    [Serializable]
    public class Injection
    {
        public string key;
        public GameObject value;
        public Injection(string _key, GameObject _value)
        {
            key = _key;
            value = _value;
        }
    }
    
    public class LuaEvnItem
    {
        public string fileName;
        public List<string> funcNames = new List<string>();
        public string luaData;
        public LuaTable luaTable;
        public LuaTable luaChildTable;
        public Injection[] injections;
        public LuaEvnItem(string _fileName, List<string> _funcNames, string _luaData, Injection[] _injections, LuaTable _luaTable, LuaTable _luaChildTable)
        {
            fileName = _fileName;
            funcNames = _funcNames;
            luaData = _luaData;
            injections = _injections;
            luaTable = _luaTable;
            luaChildTable = _luaChildTable;
        }
    }

    调用部分:

    using UnityEngine;
    using UnityEngine.UI;
    
    public class ClickBtn : MonoBehaviour
    {
        public GameObject btnObj;
    
        public GameObject image;
    
        // Start is called before the first frame update
        void Awake()
        {
            btnObj.GetComponent<Button>().onClick.AddListener(() =>
            {
                if (ClickAction != null)
                    ClickAction(new object[] {123 });
            });
            LuaManager.Instance.ToDoAction += ToDoAction;
            Injection[] injections = new Injection[] {
                    new Injection("image",image)
                };
            LuaManager.Instance.WriteByLua(this, "LuaTest", "TestFunction", injections);
        }
        Action<object[]> ClickAction;
        private void ToDoAction(string arg1, string arg2, Action<object[]> arg3)
        {
            if (arg1 == "LuaTest" && arg2 == "TestFunction")
            {
                ClickAction = arg3;
            }
        }
    }

    lua代码写到StreamingAssets/LuaScripts/LuaTest.lua里面

    function TestFunction(params)
        CS.UnityEngine.Debug.Log("Click"..(typeof(params)==nil and params[0] or ""))
    
        hue=CS.UnityEngine.Random.Range(0,1)
    
        image:GetComponent(typeof(CS.UnityEngine.UI.Image)).color=CS.UnityEngine.Color.HSVToRGB(hue,1,1)
    
        testObj=CS.UnityEngine.GameObject.CreatePrimitive(CS.UnityEngine.PrimitiveType.Cube)
    
        testObj.transform.position=CS.UnityEngine.Vector3(CS.UnityEngine.Random.Range(-10,10),CS.UnityEngine.Random.Range(-10,10),CS.UnityEngine.Random.Range(-10,10))
    end

    使用前先生成wrap代码

    生成成功以后运行即可。

    如果是移动端,改一下平台部分的路径path代码。

    emmmm.....

    其实可以直接用HotFix标签

    不过自己封装一下能实现差不多的目的,不需要打标签和添加宏定义,也会更加灵活一些。

    项目源码:https://github.com/wtb521thl/XLuaTest

    就这样。拜拜~

  • 相关阅读:
    tomcat9部署到nginx,不能通过nginx访问到tomcat
    解决Linux系统部署webapp,JavaMail 发送邮件javax.mail.MessagingException: 501 Syntax: HELO hostname问题
    先本地仓库中国添加jar包
    IDEA修改pom.xml文件不自动下载的问题
    JavaWeb路径的理解【加不加斜杠又何区别】
    IDEA好用的模板设置
    使用maven启动web项目报错
    MAVEN的学习(图片资源来自黑马程序员)
    option标签不支持单击事件
    immutable.js学习笔记(九)----- Range 与 Repeat
  • 原文地址:https://www.cnblogs.com/yzxhz/p/13628234.html
Copyright © 2011-2022 走看看