1. 程式人生 > >Unity 程式碼編譯成dll 更新dll實現熱更程式碼

Unity 程式碼編譯成dll 更新dll實現熱更程式碼

Unity 程式碼編譯成dll 更新dll實現熱更程式碼

實現流程

  • 程式碼編譯成DLL
  • DLL打包成AssetBundle
  • 載入AssetBundle
  • 載入程式碼程式集
  • 獲取指定類
  • 使用反射賦值

C#程式碼編譯成DLL

  • 使用VS建立類庫專案
    • 模版->Visual C#-> .NET Framework 3.5-> 類庫
    • 名稱即為DLL名字(反射的時候要用)
      模版->Visual C#-> .NET Framework 3.5-> 類庫
  • 引用兩個Unity相關DLL(防止編譯報錯)
    • 右鍵專案->新增->引用
      右鍵專案-><div class=
新增->引用" referrerPolicy="no-referrer">
  • 在引用管理器視窗->瀏覽->dll路徑
  • UnityEngine.dll預設路徑:C:\Program Files\Unity\Editor\Data\Managed
  • UnityEngine.UI.dll預設路徑:C:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\GUISystem
    111
  • 編寫一個繼承MonoBehaviour的簡單程式碼
  • using UnityEngine;
    using UnityEngine.UI;
    
    namespace A
    {
        public class Class1 : MonoBehaviour
        {
            public Text text;
    
            int number = 0;
    
            void Update()
            {
                if (Input.GetMouseButtonDown(0))
                {
                    number++;
                    text.text = "滑鼠左鍵按下:" + number;
                }
            }
        }
    }
    • 生成DLL
      • 右鍵專案 生成
      • 在專案的bin\Debug目錄獲得DLL

    DLL打包成AssetBundle

    • 把生成的DLL字尾修改為bytes(unity不支援dll字尾打包為AssetBundle)(下圖1)
    • 放入專案中 設定AssetBundleName(下圖2)
    • 打包程式碼(放入Editor資料夾)(下圖3)
    using UnityEngine;
    using System.Collections;
    using UnityEditor;
    using System.IO;
    
    public class BuildAssetBunble
    {
        [MenuItem("BuildAsset/Bunble")]
        public static void Build()
        {
            BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.DeterministicAssetBundle, EditorUserBuildSettings.activeBuildTarget);
    
            AssetDatabase.Refresh();
        }
    }
    • 建立StreamingAssets放入AssetBundle檔案(下圖4)
    • 點選BuildAsset/Bunble按鈕(下圖5)

    測試程式碼

    • 建立一個Text遊戲物件
    • 新建一個Test程式碼掛在到Text遊戲物件上
    
    using UnityEngine;
    using UnityEngine.UI;
    using System;
    using System.Reflection;
    
    public class Test : MonoBehaviour
    {
        void Start()
        {
            Text text = gameObject.GetComponent<Text>();//獲取組建
    
            string path = string.Empty;
    
            if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                path = Application.streamingAssetsPath + "/a_dll";
            }
            else if (Application.platform == RuntimePlatform.Android)
            {
                path = Application.streamingAssetsPath + "!assets/a_dll";
            }
    
            AssetBundle assetBundle = AssetBundle.LoadFromFile(path);//載入AssetBundle
    
            TextAsset textAsset = assetBundle.LoadAsset<TextAsset>("A");//載入AssetBundle中的A
    
    
            Assembly assembly = Assembly.Load(textAsset.bytes);//載入託管程式集
    
            Type item = assembly.GetType("A.Class1");//獲取程式集指定類
    
    
            Component comparer = gameObject.AddComponent(item);//新增到遊戲物件上
    
            FieldInfo fieldInfo = comparer.GetType().GetField("text");//使用反射獲取例項的欄位
    
            fieldInfo.SetValue(comparer, text);//給欄位賦值
        }
    }
    

    效果如下

    總結

    • 程式碼圖片都有就不上傳工程
    • 安卓測試完全沒問題
    • IOS不允許使用動態程式碼所以GG
    • 我這裡只是簡單實現了 實際上有很多限制