日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity检视面板的继承方法研究

發布時間:2025/3/8 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity检视面板的继承方法研究 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  對于檢視面板 Inspector 的面板繼承方式對項目來說是很有必要的, 比如一個基類, 寫了一個很好看的檢視面板[CustomEditor(typeof(XXX))],

可是所有子類的面板無法直接繼承這個CustomEditor, 有些人的解決方案是把子類寫檢視面板的代碼獨立出來, 然后子類面板直接去調用這些Layout,

非常浪費人力物力.

  最近發現有個 DecoratorEditor 腳本, 它實現了對 Unity 自帶檢視面板的擴展, 看到它實現某個類型的面板Inspector的方法, 就是使用Editor.CreateEditor 這個API

創建了一個相應的Editor, 然后調用它的OnInspectorGUI() 方法來繪制原有面板的, 于是可以從這個地方著手.

?  從設計上來說 [CustomEditor(typeof(XXX))] 在耦合上并沒有太多的耦合, Unity 開發組的想法應該就是一個Editor對應一個組件, 它們對應類型之間的繼承關系不應該

互相影響, 保證泛用性和獨立性.?

  原始的Editor腳本和類型是這樣的:

基類 :

public class TestBaseClass : MonoBehaviour {public float abc; }// 檢視面板 [CustomEditor(typeof(TestBaseClass))] public class TestBaseClassInspector : Editor {TestBaseClass _target;private void OnEnable(){_target = target as TestBaseClass;}public override void OnInspectorGUI(){_target.abc = EditorGUILayout.FloatField("基類變量 : ", _target.abc);} }

子類1 :

public class TestCamera : TestBaseClass {public Camera cam; }// 檢視面板 [CustomEditor(typeof(TestCamera))] public class TestCameraInspector : Editor {TestCamera _target = null;private void OnEnable(){_target = target as TestCamera;}public override void OnInspectorGUI(){base.OnInspectorGUI();_target.cam = EditorGUILayout.ObjectField("一次繼承變量 : ", _target.cam, typeof(Camera), true) as Camera;} }

子類2 :?

public class TestUntiy : TestCamera {public int hahah; }// 檢視面板 [CustomEditor(typeof(TestUntiy))] public class TestUntiyInspector : Editor {TestUntiy _target = null;private void OnEnable(){_target = target as TestUntiy;}public override void OnInspectorGUI(){base.OnInspectorGUI();_target.hahah = EditorGUILayout.IntField("二次繼承變量 : ", _target.hahah);} }

  

TestBaseClass TestCamera : TestBaseClass TestUntiy : TestCamera

非常簡單的繼承關系, TestUnity的檢視面板如下, 沒有繼承關系

?

  那么在繼承的設計上, 也應該遵循Unity的設計原則, 在繼承類型 : Editor 以及 base.OnInspectorGUI();?繪制基類方法上做文章.

如果使用簡單的繼承比如:

[CustomEditor(typeof(TestCamera))] public class TestCameraInspector : TestBaseClassInspector {TestCamera _target = null;private void OnEnable(){_target = target as TestCamera;}public override void OnInspectorGUI(){base.OnInspectorGUI();_target.cam = EditorGUILayout.ObjectField("一次繼承變量 : ", _target.cam, typeof(Camera), true) as Camera;} }

  會出現很多問題, 如基類的OnEnable方法沒有被觸發, 基類面板報錯等, 所有生命周期都要寫虛方法, 每個重寫方法都要注意, 很麻煩.

  而Editor.CreateEditor創建的Editor是有生命周期的. 創建一個中間類型 InspectorDecoratorEditor, 大家都繼承它就可以了, 而繪制基類對象的方法就改為

DrawBaseInspectorGUI<T>(), 這樣就能方便地自己定義需要繪制的基類了.

public class InspectorDecoratorEditor : Editor {public static readonly System.Type EndType = typeof(UnityEngine.MonoBehaviour); // end type dont need show in inspectorpublic static readonly System.Type BaseEditorType = typeof(UnityEditor.Editor); // CustomEditor must inherit from it, filterpublic static readonly BindingFlags CustomEditorFieldFlags = BindingFlags.NonPublic | BindingFlags.Instance; // flag// type cache[Assembly, [scriptType, customEditorType]]protected static Dictionary<Assembly, Dictionary<System.Type, System.Type>> ms_editorReferenceScript= new Dictionary<Assembly, Dictionary<System.Type, System.Type>>();protected List<Editor> m_inheritEditors = null; // cached editors// ctor, use ctor instead Mono life circle, more user friendly public InspectorDecoratorEditor(){CacheEditorReferenceScript();}#region Main Funcs/// <summary>/// Cache all CustomEditor in current Assembly/// </summary>protected void CacheEditorReferenceScript(){var editorAssembly = Assembly.GetAssembly(this.GetType()); // editor may in diferent assembliesif(ms_editorReferenceScript.ContainsKey(editorAssembly) == false){Dictionary<System.Type, System.Type> cachedData = new Dictionary<System.Type, System.Type>();var types = editorAssembly.GetExportedTypes();foreach(var editorType in types){if(editorType.IsSubclassOf(BaseEditorType)){var scriptType = GetTypeFormCustomEditor(editorType);if(scriptType != null){cachedData[scriptType] = editorType;}}}ms_editorReferenceScript[editorAssembly] = cachedData;}}/// <summary>/// Draw a Target Type Inspector, call OnInspectorGUI/// </summary>/// <typeparam name="T"></typeparam>protected virtual void DrawBaseInspectorGUI<T>() where T : InspectorDecoratorEditor{if(m_inheritEditors == null){m_inheritEditors = new List<Editor>();Dictionary<System.Type, System.Type> scriptEditorCache = null;if(ms_editorReferenceScript.TryGetValue(Assembly.GetAssembly(this.GetType()), out scriptEditorCache) && scriptEditorCache != null){var baseType = target.GetType().BaseType;while(baseType != null && baseType != EndType){System.Type editorType = null;if(scriptEditorCache.TryGetValue(baseType, out editorType) && editorType != null){m_inheritEditors.Add(Editor.CreateEditor(targets, editorType));}baseType = baseType.BaseType;}}}if(m_inheritEditors.Count > 0){for(int i = m_inheritEditors.Count - 1; i >= 0; i--){var drawTarget = m_inheritEditors[i];if(drawTarget && drawTarget.GetType() == typeof(T)){drawTarget.OnInspectorGUI(); // draw target type only, avoid endless loopbreak;}}}}#endregion#region Help Funcspublic static System.Type GetTypeFormCustomEditor(System.Type editorType){var attributes = editorType.GetCustomAttributes(typeof(CustomEditor), false) as CustomEditor[];if(attributes != null && attributes.Length > 0){var attribute = attributes[0];var type = attribute.GetType().GetField("m_InspectedType", CustomEditorFieldFlags).GetValue(attribute) as System.Type;return type;}return null;}#endregion }

  

  

  修改后的Editor代碼如下, 修改的只有繼承類以及DrawBaseInspectorGUI<T>函數, 注意這里對于T來說是沒有類型檢查的, 可是在函數中是有類型匹配的,

就算傳入錯誤類型也是安全的 :

[CustomEditor(typeof(TestBaseClass))] public class TestBaseClassInspector : InspectorDecoratorEditor {TestBaseClass _target;private void OnEnable(){_target = target as TestBaseClass;}public override void OnInspectorGUI(){_target.abc = EditorGUILayout.FloatField("基類變量 : ", _target.abc);} }[CustomEditor(typeof(TestCamera))] public class TestCameraInspector : InspectorDecoratorEditor {TestCamera _target = null;private void OnEnable(){_target = target as TestCamera;}public override void OnInspectorGUI(){DrawBaseInspectorGUI<TestBaseClassInspector>();_target.cam = EditorGUILayout.ObjectField("一次繼承變量 : ", _target.cam, typeof(Camera), true) as Camera;} }[CustomEditor(typeof(TestUntiy))] public class TestUntiyInspector : InspectorDecoratorEditor {TestUntiy _target = null;private void OnEnable(){_target = target as TestUntiy;}public override void OnInspectorGUI(){DrawBaseInspectorGUI<TestCameraInspector>();_target.hahah = EditorGUILayout.IntField("二次繼承變量 : ", _target.hahah);} }

  然后看看檢視面板現在的樣子, 完美繪制了基類面板:

DrawBaseInspectorGUI<T>() 這個繪制基類的請求強大的地方就是可以選擇從哪個類型開始繪制, 比如
DrawBaseInspectorGUI<TestCameraInspector>();
換成
DrawBaseInspectorGUI<TestBaseClassInspector>();
那么 TestCameraInspector 這個檢視面板就被跳過去了 :

?

  雖然有很多方式能夠繪制或者繼承子類檢視面板, 不過這個應該是個泛用度很高的方案. Over.

轉載于:https://www.cnblogs.com/tiancaiwrk/p/10881981.html

總結

以上是生活随笔為你收集整理的Unity检视面板的继承方法研究的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。