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

 

就这样。拜拜~

posted @ 2020-09-08 11:43  有只小耗子  阅读(940)  评论(0编辑  收藏  举报