Unity全面入門筆記11-自定義Inspector

自定義Inspector面板

Attribute自定義Inspector

  • 使用Attribute

實現下面的組件,體驗幾個Attribute的作用:

public class EditorTest : MonoBehaviour
{
    [Header("屬性標題")]
    [Tooltip("This is a property.")]
    public int property1;
    [Space(1f)]
    [Tooltip("This is another property.")]
    public int property2;
    
    [Foldout("Group")]
    public int a;
    [Foldout("Group")]
    public int b;
    [Foldout("Group")]
    public int c;
}

Header(string header)屬性可以在Inspector中增加一個粗體的標題。

Space(float hight)屬性可以在Inspector中增加一段間隔。

Tooltip(string tooltip)屬性使你在Inspector面板中將鼠標浮動在屬性上時顯示一個文字提示。

Foldout(string foldout)屬性可以在Inspector面板中渲染摺疊欄,參數名稱相同的屬性放置在同一個摺疊欄中。

組件的Editor腳本

  • 給組件綁定Editor腳本

以封裝一個邏輯判斷系統爲例展示使用Editor腳本修改組件在Inspector面板的顯示的方法。

在Project面板的根目錄下創建一個名爲"Editor"的文件夾,在其下新建腳本,命名爲LogicalSystemEditor。同樣在根目錄下創建一個名爲"Scripts"的文件夾,在其下新建腳本,命名爲LogicalSystem。打開LogicalSystemEditor,修改類型定義如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;c
using UnityEngine.UI;

[CustomEditor(typeof(LogicalSystem))]
public class LogicalSystemEditor : Editor
{
    public override void OnInspectorGUI()
    {
	}
}
  • 設計一個類

使用幾個類來封裝邏輯系統,下面的腳本使用了ScriptableObject,將來會着重學習,感興趣的可以提前瞭解:

[CreateAssetMenu]
[System.Serializable]
public class LogicalSystem : ScriptableObject
{
	public List<OrStatement> orStatement = new List<OrStatement>();
	public uint orStatementLength;
	public bool matchStatement
	{
		get
		{
			foreach(OrStatement statement in orStatement)
			{
				if(statement.matchStatement)	return true;
			}
			return false;
		} 
	}
}

[System.Serializable]
public class OrStatement
{
    public List<AndStatement> andStatement = new List<AndStatement>();
    public uint andStatementLength;
    public bool matchStatement
    {
        get
        {
        	foreach(AndStatement statement in andStatement)
        	{
         	   if(!statement.matchStatement) return false;
			}
        	return true;
   		}
    }
}

[System.Serializable]
public class AndStatement
{
    public LogicalCondition condition;
    public bool matchStatement()
    {
        switch(condition)
        {
        	//未完成,請自行補充
        }
	}
}

[System.Serializable]
public enum  LogicalCondition
{
	//未完成,請自行補充
}
  • 自定義Inspector

修改LogicalSystemEditor如下:

public class LogicalSystemEditor : Editor
{
    public override void OnInspectorGUI()
    {
    	LogicalSystem s = (LogicalSystem)target;
    	s.orStatementLength = (uint)EditorGUILayout.IntField("Conditions:", (int)s.orStatementLenth);
    	if (s.orStatementLength <= 0) s.orStatementLength = 1;
    	for (; s.orStatementLength > s.orStatement.Count;)
        {
            s.orStatement.Add(new OrStatement());
        }
        for (int i = 0; i < s.orStatementLength; i++)
        {
            OrStatement orBlock = s.orStatement[i];
            orBlock.andStatementLength = (uint)EditorGUILayout.IntField("    Or " + i, (int)orBlock.andStatementLength);
            if (orBlock.andStatementLength <= 0) orBlock.andStatementLength = 1;
            for (; orBlock.andStatementLength > orBlock.andStatement.Count;)
            {
                orBlock.andStatement.Add(new AndStatement());
            }
            for(int j = 0; j < orBlock.andStatementLength; j++)
            {
                AndStatement statement = orBlock.andStatement[j];
                statement.condition = (EffectConditionType)EditorGUILayout.EnumPopup("        And " + j, statement.condition);   
                switch(statement.condition)
                {
                    
                }
            }
        }
	}
}

在Project面板右鍵創建一個新的LogicalSystem,即可在Inspector面板觀察到自定義的結果。

  • 着重解析Editor腳本中的內容:
LogicalSystem s = (LogicalSystem)target;

在Editor腳本中,調用target屬性可以獲得我們試圖修改的那個對象,在這裏我們還需要將target拆箱,於是使用強制類型轉換,並將其保存到一個局部遍歷s中,這是爲了後面書寫的方便。

s.orStatementLength = (uint)EditorGUILayout.IntField("Conditions:", (int)s.orStatementLenth);

在此我們使用了EditorGUILayout.IntField()函數,這個函數可以在Inspector面板中繪製一個輸入整數的輸入框。函數的第一個參數用於修改這個輸入框前的文字信息,第二個參數是輸入框中值的來源,而返回值是修改後的結果。由於我們想讓這個輸入框的輸入和輸出都指向同一個屬性,所以使用了兩次s.orStatementLength。由於這個屬性是一個uint,而函數的參數和返回值類型都是int,所以使用了兩次強制類型轉換。

statement.condition = (EffectConditionType)EditorGUILayout.EnumPopup("        And " + j, statement.condition);   

在此我們又用了一個EditorGUILayout.EnumPopup函數,這個函數的作用是繪製一個Enum的下拉選框。函數的第一個參數是下拉選框前的文字信息,第二個參數是值的來源,返回值是修改後的結果。同上,我們使用了兩次一樣的屬性。由於函數返回類型爲Object,我們使用了一次強制類型轉換。

  • EditorGUILayout的其它方法
public static Rect EditorGUILayout.BeginHorizontal();
public static void EditorGUILayout.EndHorizontal();
public static Rect EditorGUILayout.BeginVertical();
public static void EditorGUILayout.EndVertical();

可以控制屬性的排版,在Begin和End中間渲染的其它Inspector組件會呈豎直或水平排版。

public static Vector2 EditorGUILayout.BeginScrollView(Vector2 scrollPosition, bool alwaysShowHorizontal, bool alwaysShowVertical);
public static void EditorGUILayout.EndScrollView(); 

渲染一個可以滾動的子面板,通過在其中鑲嵌BeginHorizontal()等函數可以更好的自定義面板。

public static Color EditorGUILayout.ColorField(string label, Color value); 

渲染一個顏色條。參數和返回值都需要填同一個對象,label指輸入框前的文字信息。

public static double EditorGUILayout.DoubleField(string label, double value); 
public static float EditorGUILayout.FloatField(string label, float value); 
public static int EditorGUILayout.FloatField(string label, int value); 

渲染一個可以輸入數值的文本框。

public static float EditorGUILayout.Slider(string label, float value, float leftValue, float rightValue); 
public static int EditorGUILayout.IntSlider(string label, int value, int leftValue, int rightValue); 

渲染一個滑動條,可以輸入或拖動數值。

public static Enum EditorGUILayout.EnumPopup(string label, Enum selected); 

渲染一個可以選擇Enum的下拉選框。注意,Enum必須具有System.Serializable標記。

public static Enum EditorGUILayout.EnumFlagsField(string label, Enum enumValue); 

渲染一個可以多選的下拉選框。適用這個方法的Enum需要特別構建:

[System.Serializable]
enum ExampleFlagsEnum
{
 None = 0, // Custom name for "Nothing" option
 A = 1 << 0,
 B = 1 << 1,
 AB = A | B, // Combination of two flags
 C = 1 << 2,
 All = ~0, // Custom name for "Everything" option
}

在ExampleFlagsEnum的渲染中,Enum的值被以位的方式解讀,選中的每個值會連續做按位或運算,並將結果輸出。注意,Enum必須具有System.Serializable標記。

public static void EditorGUILayout.Space(); 

渲染一段空行。

public static void EditorGUILayout.LabelField(string label); 

渲染一段不能修改的標題字符。

public static string EditorGUILayout.TextField(string label, string text); 
public static string EditorGUILayout.TextArea(string text); 

渲染一個可供輸入的文本框。Area是多行的,Field是單行的。

public static Vector2 EditorGUILayout.Vector2Field(string label, Vector2 value); 
public static Vector3 EditorGUILayout.Vector3Field(string label, Vector3 value); 
public static Vector4 EditorGUILayout.Vector3Field(string label, Vector4 value); 
public static Vector2Int EditorGUILayout.Vector2IntField(string label, Vector2Int value); 
public static Vector3Int EditorGUILayout.Vector3IntField(string label, Vector3Int value); 
public static Vector4Int EditorGUILayout.Vector4IntField(string label, Vector4Int value); 

渲染用於輸入向量的組合輸入框。

public static bool EditorGUILayout.Toggle(string label, bool value); 

渲染一個返回布爾類型的勾選框。

public static Object EditorGUILayout.ObjectField(string label, Object obj, Type objType, bool allowSceneObjects); 

渲染一個可以拖入任何類型的框,尤其適用於拖入ScriptableObject或MonoBehaviour。

這個方法還可以用於渲染拖入圖片的框體,如下列代碼:

target.icon = EditorGUILayout.ObjectField("Icon", target.icon, typeof(Sprite), true) as Sprite;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章