自定义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;