[英]See Enumerated Indices of Array in Unity Inspector
簡而言之,我有由枚舉中的索引引用的數組。 但是,在 Unity 的檢查器窗口中,它僅顯示“元素 0、元素 1 等”。 我希望列表顯示我的枚舉的索引值。 除非向 Unity 添加新功能,否則我想這需要一個特殊的編輯器腳本,但似乎游戲代碼甚至無法與編輯器代碼交互。 那么我該怎么做呢? 提前致謝!
所以如果我有這個:
public enum ObjectList
{
Car,
Sword,
Friends,
Depression,
NumObjects
}
[Somehow declare to use my ObjectList Enum]
public bool [] hasItem = new bool[(int)ObjectList.NumObjects];
理想情況下,檢查員現在會顯示:
Has Item
Size 4
Car []
Sword []
Friends []
Depression []
代替:
Has Item
Size 4
Element 0 []
Element 1 []
Element 2 []
Element 3 []
編輯:作為 Int Array 的附加示例(不僅僅是 bool)
Num Item
Size 4
Car 0
Sword 10
Friends 0
Depression 50
不完全是你如何描述它,但已經存在非常相似的東西:
我稍微重寫了腳本:
將此腳本放置在Assets
任何位置,例如Assets/Plugins/EnumFlag
EnumFlagAttribute.cs
using UnityEngine;
public class EnumFlagAttribute : PropertyAttribute
{
public enum FlagLayout
{
Dropdown,
List
}
public FlagLayout _layout = FlagLayout.Dropdown;
public EnumFlagAttribute() { }
public EnumFlagAttribute(FlagLayout layout)
{
_layout = layout;
}
}
並將此編輯器腳本復制到名為Editor
的文件夾中(它放在Assets
哪個位置無關緊要,只有它的名稱才重要),例如Assets/Plugins/EnumFlag/Editor
→ Unity 會自動從最終結果中排除放置在名為Editor
文件夾中的所有腳本構建因此不會由於UnityEditor
命名空間而產生構建錯誤。
EnumFlagDrawer.cs
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(EnumFlagAttribute))]
public class EnumFlagDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
if (property.propertyType == SerializedPropertyType.Enum)
{
switch (((EnumFlagAttribute)attribute)._layout)
{
case EnumFlagAttribute.FlagLayout.Dropdown:
property.intValue = EditorGUI.MaskField(position, label, property.intValue, property.enumNames);
break;
case EnumFlagAttribute.FlagLayout.List:
var buttonsIntValue = 0;
var enumLength = property.enumNames.Length;
var flagSet = new bool[enumLength];
EditorGUI.LabelField(new Rect(position.x, position.y, EditorGUIUtility.labelWidth, EditorGUIUtility.singleLineHeight), label);
EditorGUI.indentLevel++;
var posX = position.x;
EditorGUI.BeginChangeCheck();
{
for (var i = 0; i < enumLength; i++)
{
position.y += EditorGUIUtility.singleLineHeight;
// Check if the flag is currently set
if (((EnumFlagAttribute.FlagLayout)property.intValue).HasFlag((EnumFlagAttribute.FlagLayout)(1 << i)))
{
flagSet[i] = true;
}
EditorGUI.PrefixLabel(new Rect(posX, position.y, EditorGUIUtility.labelWidth, EditorGUIUtility.singleLineHeight), new GUIContent(property.enumNames[i]));
var toogePosition = new Rect(posX + EditorGUIUtility.labelWidth, position.y, EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth, EditorGUIUtility.singleLineHeight);
flagSet[i] = GUI.Toggle(toogePosition, flagSet[i], property.enumNames[i]);
if (flagSet[i])
{
buttonsIntValue += 1 << i;
}
}
}
if (EditorGUI.EndChangeCheck())
{
property.intValue = buttonsIntValue;
}
EditorGUI.indentLevel--;
break;
}
}
else
{
var color = GUI.color;
GUI.color = new Color(1f, 0.2f, 0.2f);
EditorGUI.LabelField(new Rect(position.x, position.y, EditorGUIUtility.labelWidth, position.height), label);
position.x += EditorGUIUtility.labelWidth;
EditorGUI.HelpBox(new Rect(position.x, position.y, position.width - EditorGUIUtility.labelWidth, position.height), "Use [EnumFlags] only with an enum!", MessageType.Error);
GUI.color = color;
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (((EnumFlagAttribute)attribute)._layout == EnumFlagAttribute.FlagLayout.Dropdown)
{
return EditorGUIUtility.singleLineHeight;
}
return (property.enumNames.Length + 1) * EditorGUIUtility.singleLineHeight;
}
}
然后在你的代碼中你會像這樣使用它
[System.Flags]
public enum ObjectList
{
Car = 1 << 0,
Sword = 1 << 1,
Friends = 1 << 2,
Depression = 1 << 3
}
[EnumFlag]
public ObjectList hasItem;
這會向您的 Inspector 添加一個枚舉字段,您可以在其中(取消)檢查多個值而不是一個。
請注意,很多關於此的教程手動向枚舉添加None
和All
值,但這是不必要的,因為 Unity Inspector 會自動添加它們。
或者您可以使用我剛剛添加的列表布局以適合您想要顯示的內容
[EnumFlag(EnumFlagAttribute.FlagLayout.List)]
public ObjectList hasItem;
這將枚舉字段添加為帶有相應標簽的切換列表
在腳本中設置和讀取這些按位標志的工作方式與通常的 enum 或 bool 列表略有不同:
使用按位 OR 設置多個值|
操作員:
hasItem = ObjectList.Car | ObjectList.Sword;
// or to add a value later
hasItem |= ObjectList.Friends;
使用按位 NOT ~
和 AND &
運算符刪除某個標志
hasItem &= ~ObjectList.Car;
並使用按位 XOR ^
運算符切換(反轉)某個標志:
hasItem ^= ObjectList.Car;
而不是檢查是否使用HasFlag
設置了某些標志
bool hasCar = hasItem.HasFlag(ObjectList.Car);
bool hasCarOrSword = hasItem.HasFlag(ObjectList.Car | ObjectList.Sword);
bool hasCarAndSword = hasItem.HasFlag(ObjectList.Car & ObjectList.Sword);
更新
正如您現在添加的那樣,您實際上更希望擁有一個int[]
。 這作為帶有 PropertyDrawer 的 Attribute 非常復雜,因為事實上,propertydrawer 用於該列表/數組中的每個元素而不是整個列表!
但是,您可以將列表包裝在一個類中,並為此創建一個 PropertyDrawer:
EnumIntArray.cs
using System;
[Serializable]
public class EnumIntArray
{
public string[] Names;
public int[] Values;
public EnumIntArray(Type enumType)
{
Names = Enum.GetNames(enumType);
Values = new int[Names.Length];
}
}
EnumIntArrayDrawer.cs
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(EnumIntArray), false)]
public class EnumIntArrayDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.LabelField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), label);
var values = property.FindPropertyRelative("Values");
var names = property.FindPropertyRelative("Names");
EditorGUI.indentLevel++;
for (var i = 0; i < values.arraySize; i++)
{
var name = names.GetArrayElementAtIndex(i);
var value = values.GetArrayElementAtIndex(i);
position.y += EditorGUIUtility.singleLineHeight;
var indentedRect = EditorGUI.IndentedRect(position);
EditorGUI.LabelField(new Rect(position.x, position.y, EditorGUIUtility.labelWidth, EditorGUIUtility.singleLineHeight), name.stringValue);
value.intValue = EditorGUI.IntField(new Rect(position.x + EditorGUIUtility.labelWidth - indentedRect.x / 2, position.y, EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth - indentedRect.x, EditorGUIUtility.singleLineHeight), value.intValue);
}
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var values = property.FindPropertyRelative("Values");
return (values.arraySize + 1) * EditorGUIUtility.singleLineHeight;
}
}
然后在您的腳本中使用它,例如
public EnumIntArray hasItems = new EnumIntArray(typeof(ObjectList));
並用於訪問值
var carAmount = hasItems.Values[(int)ObjectList.Car];
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.