【转载请注明出处】
BaseBehaviour(基本组件)、BaseBehaviourContainer(基本组件容器,只在编辑器下生效)、BaseScript(基本脚本,对底层接口隐藏,逻辑脚本基类)
BaseScript:主要作用是脚本统一管理,以及批处理等。
BaseBehaviourContainer:主要作用是自定义Inspector,并支持同一脚本中进行逻辑和CustomInspector的编写,同时不用暴露变量给Inspector。
效果预览:
BaseBehaviour类:
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using System;
using System.Collections;
[ExecuteInEditMode]
#if UNITY_EDITOR
[RequireComponent(typeof(BaseBehaviourContainer))]
#endif
public class BaseBehaviour : MonoBehaviour
{
#if UNITY_EDITOR
[SerializeField][HideInInspector]
private BaseBehaviourContainer mBaseBehaviourContainer;
private BaseBehaviourContainer baseBehaviourContainer
{
get
{
if(mBaseBehaviourContainer == null)
mBaseBehaviourContainer = GetComponent<BaseBehaviourContainer>();
return mBaseBehaviourContainer;
}
}
[SerializeField][HideInInspector]
private Editor mInspector;
protected Editor inspector
{
get
{
if(mInspector == null)
mInspector = Editor.CreateEditor(this);
return mInspector;
}
}
#endif
protected virtual void Awake()
{
try
{
#if UNITY_EDITOR
if(mBaseBehaviourContainer == null)
baseBehaviourContainer.AddBaseBehaviour(this);
#endif
OnAwake();
}
catch(Exception e)
{
Debug.LogException(e);
}
finally
{
}
}
protected virtual void OnAwake()
{
}
protected virtual void OnDestroy()
{
#if UNITY_EDITOR
baseBehaviourContainer.RemoveBaseBehaviour(this);
#endif
try
{
OnDestroyed();
}
catch(Exception e)
{
Debug.LogException(e);
}
finally
{
}
}
protected virtual void OnDestroyed()
{
}
#if UNITY_EDITOR
#region //Inspector
public virtual void InspectorGUI()
{
OnInspectorGUI();
}
protected virtual void OnInspectorGUI()
{
inspector.DrawDefaultInspector();
}
#endregion //Inspector
#region //Component
protected virtual void ComponentMoveUp()
{
baseBehaviourContainer.MoveUpaseBehaviour(this);
}
protected virtual void ComponentMoveDown()
{
baseBehaviourContainer.MoveDownaseBehaviour(this);
}
#endregion //Component
#endif
}
BaseScript类:
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using System.Collections;
public class BaseScript : BaseBehaviour
{
sealed protected override void Awake ()
{
base.Awake ();
}
sealed protected override void OnDestroy ()
{
base.OnDestroy ();
}
#if UNITY_EDITOR
sealed public override void InspectorGUI ()
{
base.InspectorGUI ();
}
[ContextMenu("Move Up")]
sealed protected override void ComponentMoveUp ()
{
base.ComponentMoveUp ();
}
[ContextMenu("Move Down")]
sealed protected override void ComponentMoveDown ()
{
base.ComponentMoveDown ();
}
#endif
}
BaseBehaviourContainer类:
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
[Serializable]
public sealed class BaseBehaviourInfo
{
public BaseBehaviour baseBehaviour;
public bool showInspector = true;
public BaseBehaviourInfo(BaseBehaviour baseBehaviour)
{
this.baseBehaviour = baseBehaviour;
}
}
[ExecuteInEditMode]
[DisallowMultipleComponent]
public class BaseBehaviourContainer : MonoBehaviour, IEventSystemHandler
{
[SerializeField][HideInInspector]
private List<BaseBehaviourInfo> baseBehaviourInfos = new List<BaseBehaviourInfo>();
public void AddBaseBehaviour(BaseBehaviour baseBehaviour)
{
baseBehaviour.hideFlags = HideFlags.HideInInspector;
BaseBehaviourInfo info = new BaseBehaviourInfo(baseBehaviour);
baseBehaviourInfos.Add(info);
}
public void RemoveBaseBehaviour(BaseBehaviour baseBehaviour)
{
for(int i = 0; i < baseBehaviourInfos.Count; i++)
{
BaseBehaviourInfo info = baseBehaviourInfos[i];
if(info.baseBehaviour == baseBehaviour)
{
baseBehaviourInfos.RemoveAt(i);
break;
}
}
}
public void MoveUpaseBehaviour(BaseBehaviour baseBehaviour)
{
if(baseBehaviourInfos.Count < 2)
return;
for(int i = 0; i < baseBehaviourInfos.Count; i++)
{
BaseBehaviourInfo info = baseBehaviourInfos[i];
if(info.baseBehaviour == baseBehaviour)
{
if(i > 0)
{
BaseBehaviourInfo tempInfo = baseBehaviourInfos[i - 1];
baseBehaviourInfos[i - 1] = info;
baseBehaviourInfos[i] = tempInfo;
}
break;
}
}
}
public void MoveDownaseBehaviour(BaseBehaviour baseBehaviour)
{
if(baseBehaviourInfos.Count < 2)
return;
for(int i = 0; i < baseBehaviourInfos.Count; i++)
{
BaseBehaviourInfo info = baseBehaviourInfos[i];
info.baseBehaviour.hideFlags = HideFlags.HideInInspector;
if(info.baseBehaviour == baseBehaviour)
{
if(i < baseBehaviourInfos.Count - 1)
{
BaseBehaviourInfo tempInfo = baseBehaviourInfos[i + 1];
baseBehaviourInfos[i + 1] = info;
baseBehaviourInfos[i] = tempInfo;
}
break;
}
}
}
private void Update()
{
if(baseBehaviourInfos.Count > 0)
return;
BaseBehaviour[] baseBehaviours = GetComponents<BaseBehaviour>();
for(int i = 0; i < baseBehaviours.Length; i++)
AddBaseBehaviour(baseBehaviours[i]);
if(baseBehaviourInfos.Count == 0)
DestroyImmediate(this);
}
public void OnInspectorGUI()
{
GUILayout.Space(6);
for(int i = 0; i < baseBehaviourInfos.Count; i++)
{
BaseBehaviourInfo info = baseBehaviourInfos[i];
//创建Prefab时原组件不能自动隐藏,需要在这隐藏掉,assetimport时不能获取到组件,
//并且project中inspector渲染稍慢一点,所以创建prefab后会闪一下
//暂时不清楚序列化完成的内置事件
info.baseBehaviour.hideFlags = HideFlags.HideInInspector;
try
{
EditorTools.DrawBaseBehaviourTitlebar(info);
if(info.showInspector)
{
EditorTools.BeginContents();
info.baseBehaviour.InspectorGUI();
EditorTools.EndContents();
}
}
catch(Exception e)
{
//ToDo
//双击引用时可能会异常,没有使用正常的结束组,如GUILayout.EndHorizontal(),但目前无影响
if(e.GetType().Name != "ExitGUIException")
Debug.LogException(e);
}
finally
{
}
}
}
}
#endif
BaseBehaviourContainerInspector类:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System;
[CustomEditor(typeof(BaseBehaviourContainer))]
public sealed class BaseBehaviourContainerInspector : Editor
{
BaseBehaviourContainer baseBehaviourContainer;
void OnEnable()
{
baseBehaviourContainer = target as BaseBehaviourContainer;
}
public override void OnInspectorGUI ()
{
baseBehaviourContainer.OnInspectorGUI ();
}
}
EditorTools类(根据NGUI改动):
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System.Collections;
public class EditorTools
{
public class EditorSettings
{
/// <summary>
/// Get the previously saved boolean value.
/// </summary>
static public bool GetBool (string name, bool defaultValue) { return EditorPrefs.GetBool(name, defaultValue); }
/// <summary>
/// Save the specified boolean value in settings.
/// </summary>
static public void SetBool (string name, bool val) { EditorPrefs.SetBool(name, val); }
static public bool minimalisticLook
{
get { return GetBool("NGUI Minimalistic", false); }
set { SetBool("NGUI Minimalistic", value); }
}
}
/// <summary>
/// Draw a distinctly different looking header label
/// </summary>
static public bool DrawHeader (string text) { return DrawHeader(text, text, false, EditorSettings.minimalisticLook); }
/// <summary>
/// Draw a distinctly different looking header label
/// </summary>
static public bool DrawHeader (string text, bool detailed) { return DrawHeader(text, text, detailed, !detailed); }
/// <summary>
/// Draw a distinctly different looking header label
/// </summary>
static public bool DrawHeader (string text, string key, bool forceOn, bool minimalistic)
{
bool state = EditorPrefs.GetBool(key, true);
if (!minimalistic) GUILayout.Space(3f);
if (!forceOn && !state) GUI.backgroundColor = new Color(0.8f, 0.8f, 0.8f);
GUILayout.BeginHorizontal();
GUI.changed = false;
if (minimalistic)
{
if (state) text = "\u25BC" + (char)0x200a + text;
else text = "\u25BA" + (char)0x200a + text;
GUILayout.BeginHorizontal();
GUI.contentColor = EditorGUIUtility.isProSkin ? new Color(1f, 1f, 1f, 0.7f) : new Color(0f, 0f, 0f, 0.7f);
if (!GUILayout.Toggle(true, text, "PreToolbar2", GUILayout.MinWidth(20f))) state = !state;
GUI.contentColor = Color.white;
GUILayout.EndHorizontal();
}
else
{
text = "<b><size=11>" + text + "</size></b>";
if (state) text = "\u25BC " + text;
else text = "\u25BA " + text;
if (!GUILayout.Toggle(true, text, "dragtab", GUILayout.MinWidth(20f))) state = !state;
}
if (GUI.changed) EditorPrefs.SetBool(key, state);
if (!minimalistic) GUILayout.Space(2f);
GUILayout.EndHorizontal();
GUI.backgroundColor = Color.white;
if (!forceOn && !state) GUILayout.Space(3f);
return state;
}
/// <summary>
/// Draw a distinctly different looking header BaseBehaviour
/// </summary>
static public void DrawBaseBehaviourTitlebar(BaseBehaviourInfo info)
{
GUILayout.BeginHorizontal("TE NodeBox");
info.showInspector = EditorGUILayout.InspectorTitlebar(info.showInspector, info.baseBehaviour);
GUILayout.EndHorizontal();
}
/// <summary>
/// Begin drawing the content area.
/// </summary>
static public void BeginContents () { BeginContents(EditorSettings.minimalisticLook); }
static bool mEndHorizontal = false;
/// <summary>
/// Begin drawing the content area.
/// </summary>
static public void BeginContents (bool minimalistic)
{
if (!minimalistic)
{
mEndHorizontal = true;
GUILayout.BeginHorizontal();
EditorGUILayout.BeginHorizontal("AS TextArea", GUILayout.MinHeight(10f));
}
else
{
mEndHorizontal = false;
EditorGUILayout.BeginHorizontal(GUILayout.MinHeight(10f));
GUILayout.Space(10f);
}
GUILayout.BeginVertical();
GUILayout.Space(2f);
}
/// <summary>
/// End drawing the content area.
/// </summary>
static public void EndContents ()
{
GUILayout.Space(3f);
GUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
if (mEndHorizontal)
{
GUILayout.Space(3f);
GUILayout.EndHorizontal();
}
GUILayout.Space(3f);
}
}
#endif
TestA、TestB、TestC测试类:
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using System.Collections;
public class BaseTestA : BaseScript
{
public float a;
#if UNITY_EDITOR
protected override void OnInspectorGUI ()
{
base.OnInspectorGUI();
}
#endif
}
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using System.Collections;
[System.Serializable]
public class BaseTestB : BaseScript
{
public Color colorEnter;
public Color colorNormal;
#if UNITY_EDITOR
protected override void OnInspectorGUI ()
{
base.OnInspectorGUI ();
GUILayout.Label("这是自定义Inspector");
}
#endif
}
using UnityEngine;
using System.Collections;
public class BaseTestC : BaseScript
{
public BaseTestA ta;
public BaseTestB tb;
}