天天看點

2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了

2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了

安裝xLua

插件在GITHUB上進行下載下傳。

下載下傳後的檔案目錄結構

2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  • 打開

    Assets

    檔案夾将

    Plugins

    XLua

    這兩個檔案夾Copy到Unity人更新項目中的Assets檔案夾中。
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了

    在Unity的IDE出現XLua選項

    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  • 開啟宏 HOTFIX_ENABLE

    File—>Bulid Setting—>Player Settings—>Player—>Scripting Define Symbols

    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了

    設定完成後會在出現

    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  • XLua 中的Tools 工具檔案夾 複制到熱更新工程中Assets同級目錄
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  • xLua在Unity中使用步驟
  1. 每次修改需要更新的腳本,需要運作

    Generate Code

  2. 執行

    Hotfix Inject In Editor

    ,進行Lua注入。
  • 檢查Unity 中XLua熱更新環境
  1. 引入命名空間 using XLua。
  2. 在需要更新的類上方加入标簽 [Hotfix] 。
  3. 在需要更新的方法上方加入 [LuaCallCSharp] 。
  4. 建立LuaEnv
  5. 将測試腳本HotfixTest 挂載到場景Manager總控中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System.IO;
namespace XLuaProject
{
    [Hotfix]
    public class HotfixTest : MonoBehaviour
    {
        public LuaEnv luaEnv;
        // Start is called before the first frame update
        void Start()
        {
            luaEnv = new LuaEnv();
            luaEnv.DoString("CS.UnityEngine.Debug.Log('hello world')");
            luaEnv.Dispose();
        }
    }
}
           
2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了

6. 運作

Generate Code

7. 執行

Hotfix Inject In Editor

,進行Lua注入。

8. 運作結果,lua虛拟環境搭建完畢。

2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了

安裝AssetBundles-Browser

插件在GITHUB上進行下載下傳。

1. 将插件下載下傳下來後一定注意放入Unity的目錄結構。在Unity的項目目錄中裝件Editor檔案夾。

2.将AssetBundles-Browser解壓後的Editor檔案夾Copy到Unity的項目中。目錄結構如下圖所示。

2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了

3.在Unity的IDE導覽列中的Window就會出現AssetBundles-Browser。

2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了

場景建構及描述

未更新前運作後值2s後建立一個sun物體并自轉,更新後先建立earth物體并自轉2s後建立sun并自轉,sun出現後earth圍繞sun進行公轉。

  • 建立預制體:分别建立兩個預制體earth,sun并分别設定材質。每個球體放個cube是為了看清自轉。
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  • 建立預制體腳本:自轉腳本

    Rotation

    ,公轉腳本

    Revolution

    。并将自轉腳本挂載到上述兩個預制體上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

namespace XLuaProject
{
    public class Rotation : MonoBehaviour
    {
        public static int speed = -50;
        // Start is called before the first frame update
        [LuaCallCSharp]
        void Start()
        {
        }
        // Update is called once per frame
        void Update()
        {
            transform.Rotate(0, speed * Time.deltaTime, 0, Space.Self);
        }
    }
}
           
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace XLuaProject
{
    public class Revolution : MonoBehaviour
    {
        public GameObject Axis;//軸,用于選擇圍繞中心
        public float RotateSpeed = 10;//旋轉速度// Use this for initialization
        void Start()
        {
        }
        void Update()
        {
            this.transform.RotateAround(Axis.transform.position, Vector3.up, RotateSpeed);
        }
    }
}
           
  • AssetBundle設定打包與加載。
  1. 預制體設定AssetBundle為

    sun

    ,同樣的操作将earth預制體打包命名為

    earth

    字尾命名為

    ab

    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  2. AssetBundles-Browser進行 AssetBundle資源打包。
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
    點選

    Build

    ,設定Build Target 及Output Path(輸出目錄)。
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
    檢視生成的ab包。
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  3. 加載生成AssetBundle資源包。使用LoadAB腳本進行資源加載。挂載到場景中的總控Manager中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace XLuaProject
{
    public class LoadAB : MonoBehaviour
    {
        public static Dictionary<string, GameObject> prefabDict = new Dictionary<string, GameObject>();
        // Start is called before the first frame update
        void Start()
        {
        }
        /// <summary>
        /// 加載AB資源
        /// </summary>
        /// <param name="resName">字典對象名</param>
        /// <param name="filePath">資源名</param>
        public void LoadResource(string resName, string filePath)
        {
            string path = Application.dataPath + "/AssetBundles/StandaloneWindows/" + filePath;
            AssetBundle ab = AssetBundle.LoadFromFile(path);
            GameObject gameObject = ab.LoadAsset<GameObject>(resName);
            prefabDict.Add(resName, gameObject);
        }
        public GameObject GetGameObject(string objName)
        {
            return prefabDict[objName];
        }
   
    }
}
           
  1. 加載生成AssetBundle資源包腳本的使用。建立CreateObj腳本通過LoadAB腳本進行資源加載。CreateObj腳本也挂載到總控Manager中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
namespace XLuaProject
{
    public class CreateObj : MonoBehaviour
    {
        LoadAB loadAB;
        private void Awake()
        {
            loadAB = GetComponent<LoadAB>();
        }
        // Start is called before the first frame update
        void Start()
        {
            Invoke("CreateSun", 2);
        }
        void CreateSun()
        {
            loadAB.LoadResource("sun", "sun.ab");
            GameObject gameObject = loadAB.GetGameObject("sun");
            var tempObj = Instantiate(gameObject);
            tempObj.name = "sun";
            tempObj.transform.position = new Vector3(0f, 0, 0);
        }
    }
}
           
  1. 運作結果
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
由于引入xLua的關系,每次我們修改加上熱更新辨別的腳本代碼都需要執行一遍 ,運作

Generate Code

在執行

Hotfix Inject In Editor

,進行Lua注入。否則運作報錯。

編寫熱更新腳本

官方建議方式二。

和其它配置一樣,有兩種方式

方式一:直接在類裡頭打Hotfix标簽(不建議,示例隻是為了友善示範采取這種方式);

!!注意,方式一在高版本unity不支援

方式二:在一個static類的static字段或者屬性裡頭配置一個清單。屬性可以用于實作的比較複雜的配置,比如根據Namespace做白名單。

!!注意,高版本Unity需要把配置檔案放Editor目錄下

  1. 在Assets–>Editor檔案夾中建立

    靜态類

    靜态類

    靜态類

    HotficCfg

    *因為之前忽略靜态類的這個注意事項我蹲了好久坑。 *,這個腳本使用的Namespace作為白名單進行篩選的,是以需要熱更新的腳本我都會加上命名空間

    XLuaProject

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEngine;
using XLua;

public static class HotficCfg 
{
    [Hotfix]
    public static List<Type> by_property
    {
        get
        {
            //從程式集中擷取全部類資訊
            var allTypes = Assembly.Load("Assembly-CSharp").GetTypes();
            var nameSpace = new List<string>();
            //周遊所有類篩選符合規則的命名空間
            foreach (var t in allTypes)
            {
                if (t.Namespace != null && (t.Namespace.StartsWith("XLuaProject", StringComparison.CurrentCulture)))
                {
                    if (!nameSpace.Contains(t.Namespace))
                    {
                        nameSpace.Add(t.Namespace);
                    }
                }
            }
            var retList = new List<Type>();
            var sb = new StringBuilder();
            //周遊所有類篩選所有包含該命名空間的Type對象
            foreach (var t in allTypes)
            {
                if (nameSpace.Contains(t.Namespace))
                {
                    retList.Add(t);
                    sb.AppendLine(t.FullName);
                }
            }
            //輸出所有Type資訊到項目根目錄HotTypes.txt文本中
            File.WriteAllText(Path.Combine(Application.dataPath, "../HotTypes.txt"), sb.ToString());
            return retList;
        }
    }
}
           
  1. 每次我們在執行

    Generate Code

    都會在項目根目錄也就是和Assets平級目錄下生成一個可以熱更新的類的白名單。
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  2. 在Resources建立lua檔案夾儲存lua腳本,unity中加載lua檔案要以

    .lua.txt

    結尾。
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
  3. 建立LuaEnv 腳本管理

    LuaManager

    ,自定義加載器MyLoader,lua檔案命名以

    .lua.txt

    結尾。
using System.IO;
using UnityEngine;
using XLua;
public class LuaManager : MonoBehaviour
{
    public static LuaManager _instance;
    public static LuaManager Instance
    {
        get
        {
            return _instance;
        }
    }
    [CSharpCallLua]
    public delegate void LuaDelegate(string paras);
    /// <summary>
    /// 定義一個Delegate,Lua結果将傳參回調給該Delegate
    /// </summary>
    public static LuaDelegate LuaFunc;
    /// <summary>
    /// 定義一個Lua虛拟機,建議全局唯一
    /// </summary>
    public static LuaEnv luaEnv;
    void Awake()
    {
        
       _instance = this;
       LuaEnvInit();
        
    }

    public void LuaEnvInit()
    {
        luaEnv = new LuaEnv();
        luaEnv.AddLoader(MyLoader);
        ///lua腳本的主入口
        luaEnv.DoString(@"require 'updateInfo'");
        //擷取Lua中全局function,然後映射到delegate
        luaEnv.Global.Get("LuaFunc", out LuaFunc);
    }
    private byte[] MyLoader(ref string filepath)
    {
        string abspath = Application.dataPath + "/Resources/lua/" + filepath + ".lua.txt";
        return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(abspath));
    }
   
}
           
  1. 在Unity編寫xLua腳本的注意事項。
    2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
    運作

    Generate Code

    在執行

    Hotfix Inject In Editor

    就OK了。
  2. 先來個Hello Word!在lua檔案夾中建立名為

    hello.lua.txt

xlua.hotfix(CS.XLuaProject.CreateObj,'Start',function(self)
		CS.UnityEngine.Debug.Log("Hello word!")
  end) 
           

lua腳本更新CreateObj腳本中的

Start

方法輸出"Hello word!"

2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
運作之後不再建立sun的腳本而是輸出Hello Word!
           
  1. 熱更新變量
xlua.hotfix(CS.XLuaProject.Rotation,'Start',function(self)
   ChangeCode()
end)
function ChangeCode()
   CS.XLuaProject.Rotation.speed=100
   CS.UnityEngine.Debug.Log(CS.XLuaProject.Rotation.speed)
end
           
  1. 增量熱更新加載earth的AB包,建立earth。
  • 在xLua源碼中找到util.lua.txt 并copy到Assets\Resources\lua中。
  • 建立updateInfo.lua.txt編寫腳本引入util,

    local util=require 'util'

local util=require 'util'
util.hotfix_ex(CS.XLuaProject.CreateObj,'Start',function(self)
   self.Start(self)
   -- lua 函數更新建立地球預制體
   CreateEarth(self)
end)
function CreateEarth(self)
   self.loadAB:LoadResource("earth", "earth.ab")
   local gameObject=self.loadAB:GetGameObject("earth")
   local tempObj=CS.UnityEngine.GameObject.Instantiate(gameObject)
   tempObj.name="earth"
   tempObj.transform.position = CS.UnityEngine.Vector3(-1.7, 0, 0)
end
           
  • 設定腳本中私有通路

    xlua.private_accessible(CS.XLuaProject.CreateObj)

  1. 更新updateInfo.lua.txt完整腳本
local util=require 'util'

util.hotfix_ex(CS.XLuaProject.CreateObj,'Start',function(self)
   self.Start(self)
   CreateEarth(self)
  
end)

util.hotfix_ex(CS.XLuaProject.CreateObj,'CreateSun',function(self)
   self.CreateSun(self)
    local earth=CS.UnityEngine.GameObject.Find("earth")
    local sun=CS.UnityEngine.GameObject.Find("sun")
    local dd=earth:AddComponent(typeof(CS.XLuaProject.Revolution))
    dd.Axis =sun
    dd.RotateSpeed = 3

end)

function CreateEarth(self)
   self.loadAB:LoadResource("earth", "earth.ab")
   local gameObject=self.loadAB:GetGameObject("earth")
   local tempObj=CS.UnityEngine.GameObject.Instantiate(gameObject)
   tempObj.name="earth"
   tempObj.transform.position = CS.UnityEngine.Vector3(-1.7, 0, 0)
end

xlua.hotfix(CS.XLuaProject.Rotation,'Start',function(self)
   ChangeCode()
end)
function ChangeCode()
   CS.XLuaProject.Rotation.speed=100
   CS.UnityEngine.Debug.Log(CS.XLuaProject.Rotation.speed)
end

           
2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了
1.xLua所有的配置都支援三種方式:打标簽;靜态清單;動态清單。此項目使用的是動态清單方式,
是以方法無需在打[LuaCallCSharp]的标簽。
	2.關于AssetBundle打包本篇側重點在熱更新,是以忽略了AssetBundle打包的原則。
	3.由于項目開發時間較長開發過程中解決一些坑未及時記錄,如果您按照本篇文章做下來出現問題歡迎留言讨論。
	4.最後以此文終結2020,終結疫情。
           
2020最後一篇 Unity熱更新執行個體一鏡到底,看這篇就夠了