我有一个MyClass
具有枚举和属性的类。根据枚举,我想在编辑器中显示某些属性。
有这样的枚举 { first, second} 和属性 health, step, position 。如果选择第一个,则在编辑器中显示名称和步骤,如果选择第二个,则显示步骤和位置。我想出了如何为单一行为类做到这一点。以及如何做到这一点,以使数组的每个元素都具有动态属性?图像突出显示了我在选择此列表时希望看到的字段。提前致谢 。对不起我的英语不好
我有一个MyClass
具有枚举和属性的类。根据枚举,我想在编辑器中显示某些属性。
有这样的枚举 { first, second} 和属性 health, step, position 。如果选择第一个,则在编辑器中显示名称和步骤,如果选择第二个,则显示步骤和位置。我想出了如何为单一行为类做到这一点。以及如何做到这一点,以使数组的每个元素都具有动态属性?图像突出显示了我在选择此列表时希望看到的字段。提前致谢 。对不起我的英语不好
这是一个使用ReaorderableList
from的示例UnityEditorInternal
(我基本上是使用这个很酷的 turorial 学习的),我发现它比直接在OnInspectorGUI
.
顾名思义,还有一个附加功能:可以使用拖放来选择元素并使其可重新排序!
List 元素的类
[Serializeable]
puclic class YourClass
{
public enum YourEnum
{
first,
second
}
public YourEnum Enum;
public string Name;
public int Step;
public Vector3 Position;
}
包含列表的类
public class YourOtherClass : MonoBehaviour
{
public List<YourClass> YourList = new List<YourClass>();
// It works the same for arrays if you prefere that, no need to change the inspector
// Note that in this case you can't initalize it here yet but the Inspector does that for you
// public YourClass[] YourList ;
}
编辑
[CustomEditor(typeof(YourOtherClass))]
public class YourOtherClassEditor : Editor
{
// This will be the serialized "copy" of YourOtherClass.YourList
private SerializedProperty YourList;
private ReorderableList YourReorderableList;
private void OnEnable()
{
// Step 1 "link" the SerializedProperties to the properties of YourOtherClass
YourList = serializedObject.FindProperty("YourList");
// Step 2 setup the ReorderableList
YourReorderableList = new ReorderableList(serializedObject, YourList)
{
// Can your objects be dragged an their positions changed within the List?
draggable = true,
// Can you add elements by pressing the "+" button?
displayAdd = true,
// Can you remove Elements by pressing the "-" button?
displayRemove = true,
// Make a header for the list
drawHeaderCallback = rect =>
{
EditorGUI.LabelField(rect, "This are your Elements");
},
// Now to the interesting part: Here you setup how elements look like
drawElementCallback = (rect, index, active, focused) =>
{
// Get the currently to be drawn element from YourList
var element = YourList.GetArrayElementAtIndex(index);
// Get the elements Properties into SerializedProperties
var Enum = element.FindPropertyRelative("Enum");
var Name = element.FindPropertyRelative("Name");
var Step = element.FindPropertyRelative("Step");
var Position = element.FindPropertyRelative("Position");
// Draw the Enum field
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), Enum);
// start the next property in the next line
rect.y += EditorGUIUtility.singleLineHeight;
// only show Name field if selected "first"
if ((YourClass.YourEnum)Enum.intValue == YourClass.YourEnum.first)
{
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), Name);
// start the next property in the next line
rect.y += EditorGUIUtility.singleLineHeight;
}
// Draw the Step field
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), Step);
// start the next property in the next line
rect.y += EditorGUIUtility.singleLineHeight;
// only show Step field if selected "seconds"
if ((YourClass.YourEnum)Enum.intValue == YourClass.YourEnum.second)
{
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), Position);
}
},
// And since we have more than one line (default) you'll have to configure
// how tall your elements are. Luckyly in your example it will always be exactly
// 3 Lines in each case. If not you would have to change this.
// In some cases it becomes also more readable if you use one more Line as spacer between the elements
elementHeight = EditorGUIUtility.singleLineHeight * 3,
//alternatively if you have different heights you would use e.g.
//elementHeightCallback = index =>
//{
// var element = YourList.GetArrayElementAtIndex(index);
// var Enum = element.FindPropertyRelative("Enum");
// switch ((YourClass.YourEnum)Enum.intValue)
// {
// case YourClass.YourEnum.first:
// return EditorGUIUtility.singleLineHeight * 3;
// case YourClass.YourEnum.second:
// return EditorGUIUtility.singleLineHeight * 5;
// default:
// return EditorGUIUtility.singleLineHeight;
// }
//}
// optional: Set default Values when adding a new element
// (otherwise the values of the last list item will be copied)
onAddCallback = list =>
{
// The new index will be the current List size ()before adding
var index = list.serializedProperty.arraySize;
// Since this method overwrites the usual adding, we have to do it manually:
// Simply counting up the array size will automatically add an element
list.serializedProperty.arraySize++;
list.index = index;
var element = list.serializedProperty.GetArrayElementAtIndex(index);
// again link the properties of the element in SerializedProperties
var Enum = element.FindPropertyRelative("Enum");
var Name = element.FindPropertyRelative("Name");
var Step = element.FindPropertyRelative("Step");
var Position = element.FindPropertyRelative("Position");
// and set default values
Enum.intValue = (int) YourClass.YourEnum.first;
Name.stringValue = "";
Step.intValue = 0;
Position.vector3Value = Vector3.zero;
}
};
}
public override void OnInspectorGUI()
{
// copy the values of the real Class to the linked SerializedProperties
serializedObject.Update();
// print the reorderable list
YourReorderableList.DoLayoutList();
// apply the changed SerializedProperties values to the real class
serializedObject.ApplyModifiedProperties();
}
}
不要忘记使用
using UnityEditor;
using UnityEditorInternal;
结果:
假设MyClass
定义如下:
public class MyClass {
public enum MyEnumType {first, second} ;
public MyEnumType enumNumber;
public String name;
public int step;
public Vector3 position;
}
分为三个步骤:
MyCustomList
// Script name : MyCustomList.cs
using UnityEngine;
using System;
using System.Collections.Generic; // Import the System.Collections.Generic class to give us access to List<>
public class MyCustomList: MonoBehaviour {
//This is our list we want to use to represent our class as an array.
public List<MyClass> MyList = new List<MyClass>(1);
}
MyCustomListEditor
// Script name : MyCustomListEditor.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
[CustomEditor(typeof(MyCustomList))]
public class MyCustomListEditor : Editor {
MyCustomList t;
SerializedObject GetTarget;
SerializedProperty ThisList;
int ListSize;
void OnEnable(){
t = (MyCustomList)target;
GetTarget = new SerializedObject(t);
ThisList = GetTarget.FindProperty("MyList"); // Find the List in our script and create a reference of it
}
public override void OnInspectorGUI(){
//Update our list
GetTarget.Update();
//Resize our list
EditorGUILayout.Space ();
EditorGUILayout.Space ();
ListSize = ThisList.arraySize;
ListSize = EditorGUILayout.IntField ("List Size", ListSize);
if(ListSize != ThisList.arraySize){
while(ListSize > ThisList.arraySize){
ThisList.InsertArrayElementAtIndex(ThisList.arraySize);
}
while(ListSize < ThisList.arraySize){
ThisList.DeleteArrayElementAtIndex(ThisList.arraySize - 1);
}
}
EditorGUILayout.Space ();
EditorGUILayout.Space ();
//Display our list to the inspector window
for(int i = 0; i < ThisList.arraySize; i++){
SerializedProperty MyListRef = ThisList.GetArrayElementAtIndex(i);
SerializedProperty MyEnum= MyListRef.FindPropertyRelative("enumName");
SerializedProperty MyName = MyListRef.FindPropertyRelative("name");
SerializedProperty MyStep = MyListRef.FindPropertyRelative("step");
SerializedProperty MyPosition = MyListRef.FindPropertyRelative("position");
EditorGUILayout.PropertyField(MyEnum);
int MyEnumIndex = MyEnum.enumValueIndex;
// Show/hide the properties based on the index of the enumValue.
if (MyEnumIndex == (int)MyClass.MyEnumType.first) {
EditorGUILayout.PropertyField(MyName);
}
if (MyEnumIndex == (int)MyClass.MyEnumType.second) {
EditorGUILayout.PropertyField(MyPosition);
}
EditorGUILayout.PropertyField(MyStep);
EditorGUILayout.Space ();
//Remove this index from the List
if(GUILayout.Button("Remove This Index (" + i.ToString() + ")")){
ThisList.DeleteArrayElementAtIndex(i);
}
EditorGUILayout.Space ();
EditorGUILayout.Space ();
EditorGUILayout.Space ();
EditorGUILayout.Space ();
}
//Apply the changes to our list
GetTarget.ApplyModifiedProperties();
}
}
BigClass
改为使用MyCustomList
代替List<MyClass>
public class BigClass : MonoBehaviour {
MyCustomList myList = new MyCustomList();
// .. Whatever else is in BigClass
}
这是从Unity 论坛上的这篇文章中采用的。