2024-07-14 Unity插件 Odin Inspector2 —— Essential Attributes

1 说明

​ 本章介绍 Odin Inspector 插件中重要特性的使用方法。

2 重要特性

2.1 AssetsOnly / SceneObjectsOnly

使目标对象在 Inspector 窗口中只能关联资源 / 场景对象,限制拖拽的资源类型。

image-20240715004717713
// SceneAndAssetsOnlyExamplesComponent.cs

using Sirenix.OdinInspector;
using System.Collections.Generic;
using UnityEngine;

public class SceneAndAssetsOnlyExamplesComponent : MonoBehaviour
{
    [Title("Assets only")]
    [AssetsOnly]
    public List<GameObject> OnlyPrefabs;

    [AssetsOnly]
    public GameObject SomePrefab;

    [AssetsOnly]
    public Material MaterialAsset;

    [AssetsOnly]
    public MeshRenderer SomeMeshRendererOnPrefab;

    [Title("Scene Objects only")]
    [SceneObjectsOnly]
    public List<GameObject> OnlySceneObjects;

    [SceneObjectsOnly]
    public GameObject SomeSceneObject;

    [SceneObjectsOnly]
    public MeshRenderer SomeMeshRenderer;
}

2.2 CustomValueDrawer

自定义属性的显示方式。

  • string action

    显示属性的方法名。

image-20240715004812602
  1. action 方法中写 GUI 的显示逻辑,并返回字段的值。
  2. 该特性应用于数组时,将对数组的每个元素应用一次。
  3. 使用该特性时,需要配合 UNITY_EDITOR 指令,用法如下。
// CustomValueDrawerExamplesComponent.cs

using Sirenix.OdinInspector;
using System;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR // Editor namespaces can only be used in the editor.
using Sirenix.Utilities.Editor;
using UnityEditor;
#endif

public class CustomValueDrawerExamplesComponent : MonoBehaviour
{
    public float From = 2, To = 7;

    [CustomValueDrawer("MyCustomDrawerStatic")]
    public float CustomDrawerStatic;

    [CustomValueDrawer("MyCustomDrawerInstance")]
    public float CustomDrawerInstance;

    [CustomValueDrawer("MyCustomDrawerAppendRange")]
    public float AppendRange;

    [CustomValueDrawer("MyCustomDrawerArrayNoLabel")]
    public float[] CustomDrawerArrayNoLabel = new float[] { 3f, 5f, 6f };

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    private static float MyCustomDrawerStatic(float value, GUIContent label) {
        return EditorGUILayout.Slider(label, value, 0f, 10f);
    }

    private float MyCustomDrawerInstance(float value, GUIContent label) {
        return EditorGUILayout.Slider(label, value, this.From, this.To);
    }

    private float MyCustomDrawerAppendRange(float value, GUIContent label, Func<GUIContent, bool> callNextDrawer) {
        SirenixEditorGUI.BeginBox();
        callNextDrawer(label);
        var result = EditorGUILayout.Slider(value, this.From, this.To);
        SirenixEditorGUI.EndBox();
        return result;
    }

    private float MyCustomDrawerArrayNoLabel(float value) {
        return EditorGUILayout.Slider(value, this.From, this.To);
    }
#endif
}

2.3 OnValueChanged

在检查器中编辑属性时,延迟对属性应用更改。更改值时,不会应用(黄色显示)。仅更改完成后,才会应用该值。

类似于 Unity 的内置延迟属性,但此特性也可以应用于属性。

image-20240715005217404
// DelayedPropertyExampleComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class DelayedPropertyExampleComponent : MonoBehaviour
{
    // Delayed and DelayedProperty attributes are virtually identical...
    [Delayed]
    [OnValueChanged("OnValueChanged")]
    public int DelayedField;

    // ... but the DelayedProperty can, as the name suggests, also be applied to properties.
    [ShowInInspector, DelayedProperty]
    [OnValueChanged("OnValueChanged")]
    public string DelayedProperty { get; set; }

    private void OnValueChanged() {
        Debug.Log("Value changed!");
    }
}

2.4 DetailedInfoBox

为属性设置消息盒。

  • string message

    默认显示的信息。

  • string details

    点击后展开显示的详细信息。

  • InfoMessageType infoMessageType = InfoMessageType.Info

    消息盒种类。

  • string visibleIf = null

    如果表达式为 true,则显示,否则不显示。

image-20240715005253530
// DetailedInfoBoxExampleComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class DetailedInfoBoxExampleComponent : MonoBehaviour
{
    [DetailedInfoBox("Click the DetailedInfoBox...",
        "... to reveal more information!\n" +
        "This allows you to reduce unnecessary clutter in your editors, and still have all the relavant information available when required.")]
    public int Field;
}

2.5 EnableGUI

激活 GUI 交互,使得能够在 Inspector 窗口进行编辑。

image-20240715005345457
// EnableGUIExampleComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class EnableGUIExampleComponent : MonoBehaviour
{
    [ShowInInspector]
    public int GUIDisabledProperty { get { return 10; } }
    
    [ShowInInspector, EnableGUI]
    public int GUIEnabledProperty { get { return 10; } }
}

2.6 GUIColor

为 GUI 上色。

  • float r, float g, float b, float a = 1f

    使用 RGBA 指定颜色。

  • string getColor

    指定颜色名。

image-20240715005438314
// GUIColorExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class GUIColorExamplesComponent : MonoBehaviour
{
    [GUIColor(0.3f, 0.8f, 0.8f, 1f)]
    public int ColoredInt1;

    [GUIColor(0.3f, 0.8f, 0.8f, 1f)]
    public int ColoredInt2;

    [GUIColor("#FF0000")]
    public int Hex1;

    [GUIColor("#FF000077")]
    public int Hex2;

    [GUIColor("RGB(0, 1, 0)")]
    public int Rgb;

    [GUIColor("RGBA(0, 1, 0, 0.5)")]
    public int Rgba;

    [GUIColor("orange")]
    public int NamedColors;

    [ButtonGroup]
    [GUIColor(0, 1, 0)]
    private void Apply() { }

    [ButtonGroup]
    [GUIColor(1, 0.6f, 0.4f)]
    private void Cancel() { }

    [InfoBox("You can also reference a color member to dynamically change the color of a property.")]
    [GUIColor("GetButtonColor")]
    [Button("I Am Fabulous", ButtonSizes.Gigantic)]
    private static void IAmFabulous() { }

    [Button(ButtonSizes.Large)]
    [GUIColor("@Color.Lerp(Color.red, Color.green, Mathf.Abs(Mathf.Sin((float)EditorApplication.timeSinceStartup)))")]
    private static void Expressive() { }

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    private static Color GetButtonColor() {
        Sirenix.Utilities.Editor.GUIHelper.RequestRepaint();
        return Color.HSVToRGB(Mathf.Cos((float)UnityEditor.EditorApplication.timeSinceStartup + 1f) * 0.225f + 0.325f, 1, 1);
    }
#endif
}

2.7 HideLabel

隐藏属性名。

image-20240715005523963
// HideLabelExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class HideLabelExamplesComponent : MonoBehaviour
{
    [Title("Wide Colors")]
    [HideLabel]
    [ColorPalette("Fall")]
    public Color WideColor1;

    [HideLabel]
    [ColorPalette("Fall")]
    public Color WideColor2;

    [Title("Wide Vector")]
    [HideLabel]
    public Vector3 WideVector1;

    [HideLabel]
    public Vector4 WideVector2;

    [Title("Wide String")]
    [HideLabel]
    public string WideString;

    [Title("Wide Multiline Text Field")]
    [HideLabel]
    [MultiLineProperty]
    public string WideMultilineTextField = "";
}

2.8 PropertyOrder

指定属性显示的顺序。

  • float order

    显示顺序,从小到大排列。

image-20240715005613267
// PropertyOrderExamplesComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class PropertyOrderExamplesComponent : MonoBehaviour
{
    [PropertyOrder(1)]
    public int Second;
    
    [InfoBox("PropertyOrder is used to change the order of properties in the inspector.")]
    [PropertyOrder(-1)]
    public int First;
}

2.9 PropertySpace

指定属性显示的间距。

  • float spaceBefore

    上间距。

  • float spaceAfter

    下间距。

image-20240715005654521
// SpaceExampleComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class SpaceExampleComponent : MonoBehaviour
{
    // PropertySpace and Space attributes are virtually identical.
    [Space]
    [BoxGroup("Space", ShowLabel = false)]
    public int Space;
    
    // You can also control spacing both before and after the PropertySpace attribute.
    [PropertySpace(SpaceBefore = 30, SpaceAfter = 60)]
    [BoxGroup("BeforeAndAfter", ShowLabel = false)]
    public int BeforeAndAfter;
    
    // The PropertySpace attribute can, as the name suggests, also be applied to properties.
    [PropertySpace]
    [ShowInInspector, BoxGroup("Property", ShowLabel = false)]
    public string Property { get; set; }
}

2.10 ReadOnly

只在 Inspector 窗口显示,而不能改变值。

image-20240715005738889
// ReadOnlyExamplesComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class ReadOnlyExamplesComponent : MonoBehaviour
{
    [ReadOnly]
    public string MyString = "This is displayed as text";
    
    [ReadOnly]
    public int MyInt = 9001;
    
    [ReadOnly]
    public int[] MyIntList = new int[] { 1, 2, 3, 4, 5, 6, 7, };
}

2.11 Required

如果对象没有关联值,则显示信息。

  • string errorMessage

    显示信息。

  • InfoMessageType messageType

    信息类型。

image-20240715005824011
// RequiredExamplesComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class RequiredExamplesComponent : MonoBehaviour
{
    [Required]
    public GameObject MyGameObject;
    
    [Required("Custom error message.")]
    public Rigidbody MyRigidbody;
    
    [InfoBox("Use $ to indicate a member string as message.")]
    [Required("$DynamicMessage")]
    public GameObject GameObject;
    
    public string DynamicMessage = "Dynamic error message";
}

2.12 RequiredIn(*)

说实话,看了半天没看懂。。。

image-20240715005906461
// RequiredInAttributeExamplesComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class RequiredInAttributeExamplesComponent : MonoBehaviour
{
    [RequiredIn(PrefabKind.InstanceInScene, ErrorMessage = "Error messages can be customized. Odin expressions is supported.")]
    public string InstanceInScene = "Instances of prefabs in scenes";
    
    [RequiredIn(PrefabKind.InstanceInPrefab)]
    public string InstanceInPrefab = "Instances of prefabs nested inside other prefabs";
    
    [RequiredIn(PrefabKind.Regular)]
    public string Regular = "Regular prefab assets";
    
    [RequiredIn(PrefabKind.Variant)]
    public string Variant = "Prefab variant assets";
    
    [RequiredIn(PrefabKind.NonPrefabInstance)]
    public string NonPrefabInstance = "Non-prefab component or gameobject instances in scenes";
    
    [RequiredIn(PrefabKind.PrefabInstance)]
    public string PrefabInstance = "Instances of regular prefabs, and prefab variants in scenes or nested in other prefabs";
    
    [RequiredIn(PrefabKind.PrefabAsset)]
    public string PrefabAsset = "Prefab assets and prefab variant assets";
    
    [RequiredIn(PrefabKind.PrefabInstanceAndNonPrefabInstance)]
    public string PrefabInstanceAndNonPrefabInstance = "Prefab Instances, as well as non-prefab instances";
}

2.13 Searchable

可查询 chiledren 的类型和名称。

  • bool FuzzySearch = true

    是否使用模糊字符串匹配进行搜索。

  • SearchFilterOptions FilterOptions = SearchFilterOptions.All

    搜索方式。

  • bool Recursive = true

    是递归搜索,还是只搜索顶级属性。

image-20240715010054683
// SearchablePerksExampleComponent.cs

using Sirenix.OdinInspector;
using System;
using System.Collections.Generic;
using UnityEngine;

public class SearchablePerksExampleComponent : MonoBehaviour
{
    [Searchable]
    public List<Perk> Perks = new List<Perk>() {
        new Perk() {
            Name = "Old Sage",
            Effects = new List<Effect>() {
                new Effect() { Skill = Skill.Wisdom, Value       = 2, },
                new Effect() { Skill = Skill.Intelligence, Value = 1, },
                new Effect() { Skill = Skill.Strength, Value     = -2 },
            },
        },
        new Perk() {
            Name = "Hardened Criminal",
            Effects = new List<Effect>() {
                new Effect() { Skill = Skill.Dexterity, Value = 2, },
                new Effect() { Skill = Skill.Strength, Value  = 1, },
                new Effect() { Skill = Skill.Charisma, Value  = -2 },
            },
        },
        new Perk() {
            Name = "Born Leader",
            Effects = new List<Effect>() {
                new Effect() { Skill = Skill.Charisma, Value     = 2, },
                new Effect() { Skill = Skill.Intelligence, Value = -3 },
            },
        },
        new Perk() {
            Name = "Village Idiot",
            Effects = new List<Effect>() {
                new Effect() { Skill = Skill.Charisma, Value     = 4, },
                new Effect() { Skill = Skill.Constitution, Value = 2, },
                new Effect() { Skill = Skill.Intelligence, Value = -3 },
                new Effect() { Skill = Skill.Wisdom, Value       = -3 },
            },
        },
    };

    [Serializable]
    public class Perk
    {
        public string Name;

        [TableList]
        public List<Effect> Effects;
    }

    [Serializable]
    public class Effect
    {
        public Skill Skill;
        public float Value;
    }

    public enum Skill
    {
        Strength,
        Dexterity,
        Constitution,
        Intelligence,
        Wisdom,
        Charisma,
    }
}

2.14 ShowInInspector

在 Inspector 窗口中显示任意成员。

注意:

​ ShowInInspector 不会序列化成员,仅使用该特性不会保存任何改动。

image-20240715010414020
// ShowPropertiesInTheInspectorExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class ShowPropertiesInTheInspectorExamplesComponent : MonoBehaviour
{
    [SerializeField, HideInInspector]
    private int evenNumber;

    [ShowInInspector]
    public int EvenNumber {
        get { return this.evenNumber; }
        set { this.evenNumber = value - (value % 2); }
    }
}

2.15 Title

在属性上方显示标题。

  • string title

    标题名。

  • string subtitle = null

    副标题。

  • TitleAlignments titleAlignment = TitleAlignments.Left

    对齐方式。

  • bool horizontalLine = true

    是否显示水平线。

  • bool bold = true

    标题是否加粗显示。

image-20240715010618848
// TitleExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class TitleExamplesComponent : MonoBehaviour
{
    [Title("Titles and Headers")]
    public string MyTitle = "My Dynamic Title";

    public string MySubtitle = "My Dynamic Subtitle";

    [Title("Static title")]
    public int C;

    public int D;

    [Title("Static title", "Static subtitle")]
    public int E;

    public int F;

    [Title("$MyTitle", "$MySubtitle")]
    public int G;

    public int H;

    [Title("Non bold title", "$MySubtitle", bold: false)]
    public int I;

    public int J;

    [Title("Non bold title", "With no line seperator", horizontalLine: false, bold: false)]
    public int K;

    public int L;

    [Title("$MyTitle", "$MySubtitle", TitleAlignments.Right)]
    public int M;

    public int N;

    [Title("$MyTitle", "$MySubtitle", TitleAlignments.Centered)]
    public int O;

    public int P;

    [Title("@DateTime.Now.ToString(\"dd:MM:yyyy\")", "@DateTime.Now.ToString(\"HH:mm:ss\")")]
    public int Expression;

    [ShowInInspector]
    [Title("Title on a Property")]
    public int S { get; set; }

    [Title("Title on a Method")]
    [Button]
    public void DoNothing() { }
}

2.16 TypeFilter

依据类型显示属性。

  • string filterGetter

    获取显示属性的方法。

image-20240715010719942
// TypeFilterExamplesComponent.cs
using Sirenix.OdinInspector;
using Sirenix.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class TypeFilterExamplesComponent : SerializedMonoBehaviour
{
    [TypeFilter("GetFilteredTypeList")]
    public BaseClass A, B;
    
    [TypeFilter("GetFilteredTypeList")]
    public BaseClass[] Array = new BaseClass[3];
    
    public IEnumerable<Type> GetFilteredTypeList()
    {
        var q = typeof(BaseClass).Assembly.GetTypes()
            .Where(x => !x.IsAbstract)                                          // Excludes BaseClass
            .Where(x => !x.IsGenericTypeDefinition)                             // Excludes C1<>
            .Where(x => typeof(BaseClass).IsAssignableFrom(x));                 // Excludes classes not inheriting from BaseClass
    
        // Adds various C1<T> type variants.
        q = q.AppendWith(typeof(C1<>).MakeGenericType(typeof(GameObject)));
        q = q.AppendWith(typeof(C1<>).MakeGenericType(typeof(AnimationCurve)));
        q = q.AppendWith(typeof(C1<>).MakeGenericType(typeof(List<float>)));
    
        return q;
    }
    
    public abstract class BaseClass
    {
        public int BaseField;
    }
    
    public class A1 : BaseClass { public int _A1; }
    public class A2 : A1 { public int _A2; }
    public class A3 : A2 { public int _A3; }
    public class B1 : BaseClass { public int _B1; }
    public class B2 : B1 { public int _B2; }
    public class B3 : B2 { public int _B3; }
    public class C1<T> : BaseClass { public T C; }
}

2.17 TypeInfoBox

在类型的每个示例顶部绘制一个信息框。

  • string message

    绘制的信息。

image-20240715010844080
// TypeInfoBoxExampleComponent.cs

using Sirenix.OdinInspector;
using System;
using UnityEngine;

#if UNITY_EDITOR // Editor namespaces can only be used in the editor.
using Sirenix.OdinInspector.Editor.Examples;
#endif

public class TypeInfoBoxExampleComponent : MonoBehaviour
{
    public MyType MyObject = new MyType();

#if UNITY_EDITOR // MyScriptyScriptableObject is an example type and only exists in the editor
    [InfoBox("Click the pen icon to open a new inspector for the Scripty object.")]
    [InlineEditor]
    public MyScriptyScriptableObject Scripty;
#endif

    [Serializable]
    [TypeInfoBox("The TypeInfoBox attribute can be put on type definitions and will result in an InfoBox being drawn at the top of a property.")]
    public class MyType
    {
        public int Value;
    }

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    [OnInspectorInit]
    private void CreateData() {
        Scripty = ExampleHelper.GetScriptableObject<MyScriptyScriptableObject>("Scripty");
    }

    [OnInspectorDispose]
    private void CleanupData() {
        if (Scripty != null) UnityEngine.Object.DestroyImmediate(Scripty);
    }
#endif
}

2.18 ValidateInput

允许检查 Inspector 窗口中拖拽关联值是否正确。

  • string condition

    判断是否正确的方法。

  • string defaultMessage

    显示信息。

  • InfoMessageType messageType

    信息类型。

image-20240715011220919
// ValidateInputExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

#if UNITY_EDITOR // Editor namespaces can only be used in the editor.
using Sirenix.OdinInspector.Editor.Examples;
#endif

public class ValidateInputExamplesComponent : MonoBehaviour
{
#if UNITY_EDITOR // MyScriptyScriptableObject is an example type and only exists in the editor
    [HideLabel]
    [Title("Default message", "You can just provide a default message that is always used")]
    [ValidateInput("MustBeNull", "This field should be null.")]
    public MyScriptyScriptableObject DefaultMessage;
#endif

    [Space(12), HideLabel]
    [Title("Dynamic message", "Or the validation method can dynamically provide a custom message")]
    [ValidateInput("HasMeshRendererDynamicMessage", "Prefab must have a MeshRenderer component")]
    public GameObject DynamicMessage;

    [Space(12), HideLabel]
    [Title("Dynamic message type", "The validation method can also control the type of the message")]
    [ValidateInput("HasMeshRendererDynamicMessageAndType", "Prefab must have a MeshRenderer component")]
    public GameObject DynamicMessageAndType;

    [Space(8), HideLabel]
    [InfoBox("Change GameObject value to update message type", InfoMessageType.None)]
    public InfoMessageType MessageType;

    [Space(12), HideLabel]
    [Title("Dynamic default message", "Use $ to indicate a member string as default message")]
    [ValidateInput("AlwaysFalse", "$Message", InfoMessageType.Warning)]
    public string Message = "Dynamic ValidateInput message";

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    private bool AlwaysFalse(string value) {
        return false;
    }

    private bool MustBeNull(MyScriptyScriptableObject scripty) {
        return scripty == null;
    }

    private bool HasMeshRendererDefaultMessage(GameObject gameObject) {
        if (gameObject == null) return true;

        return gameObject.GetComponentInChildren<MeshRenderer>() != null;
    }

    private bool HasMeshRendererDynamicMessage(GameObject gameObject, ref string errorMessage) {
        if (gameObject == null) return true;

        if (gameObject.GetComponentInChildren<MeshRenderer>() == null) {
            // If errorMessage is left as null, the default error message from the attribute will be used
            errorMessage = "\"" + gameObject.name + "\" must have a MeshRenderer component";

            return false;
        }

        return true;
    }

    private bool HasMeshRendererDynamicMessageAndType(GameObject gameObject, ref string errorMessage, ref InfoMessageType? messageType) {
        if (gameObject == null) return true;

        if (gameObject.GetComponentInChildren<MeshRenderer>() == null) {
            // If errorMessage is left as null, the default error message from the attribute will be used
            errorMessage = "\"" + gameObject.name + "\" should have a MeshRenderer component";

            // If messageType is left as null, the default message type from the attribute will be used
            messageType = this.MessageType;

            return false;
        }

        return true;
    }
#endif
}

2.19 ValueDropdown

创建下拉列表,以供在 Inspector 面板上选择对应的值。

  • string valuesGetter

    获取下拉列表可选值的方法。返回值可以是数组,或者 ValueDropdownList<T> 的 IEnumerable。

    ValueDropdownList 的成员为 ValueDropdownItem,其成员 Text 为显示在 Inspector 窗口上对应值 Value 的信息。

  • bool AppendNextDrawer = false

    如果为 true,则改为用小按钮开启下拉列表,而不是用宽按钮。

  • bool DisableGUIInAppendedDrawer = false

    是否可以在 Inspector 窗口上编辑值。

  • bool ExpandAllMenuItems = false

    如果为 true,则下拉菜单呈现树状图,用 ‘/’ 号表示父子关系。

  • bool DrawDropdownForListElements = true

    如果对象为列表,则需禁用此属性,以正常显示子元素。

  • bool IsUniqueList = false

    对象为列表时,其内容是否唯一,不可重复。

  • bool ExcludeExistingValuesInList = false

    如果对象为列表,且 IsUniqueList 为 true,则启用此属性将排除现有值;

    否则,将显示一个复选框,指示该项是否已包含。

image-20240715011330407
// ValueDropdownExamplesComponent.cs

using Sirenix.OdinInspector;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class ValueDropdownExamplesComponent : MonoBehaviour
{
    [ValueDropdown("TextureSizes")]
    public int SomeSize1;

    [ValueDropdown("FriendlyTextureSizes")]
    public int SomeSize2;

    [ValueDropdown("FriendlyTextureSizes", AppendNextDrawer = true, DisableGUIInAppendedDrawer = true)]
    public int SomeSize3;

    [ValueDropdown("GetListOfMonoBehaviours", AppendNextDrawer = true)]
    public MonoBehaviour SomeMonoBehaviour;

    [ValueDropdown("KeyCodes")]
    public KeyCode FilteredEnum;

    [ValueDropdown("TreeViewOfInts", ExpandAllMenuItems = true)]
    public List<int> IntTreview = new List<int>() { 1, 2, 7 };

    [ValueDropdown("GetAllSceneObjects", IsUniqueList = true)]
    public List<GameObject> UniqueGameobjectList;

    [ValueDropdown("GetAllSceneObjects", IsUniqueList = true, DropdownTitle = "Select Scene Object", DrawDropdownForListElements = false, ExcludeExistingValuesInList = true)]
    public List<GameObject> UniqueGameobjectListMode2;

#if UNITY_EDITOR        // Editor-related code must be excluded from builds
#pragma warning disable // And these members are in fact being used, though the compiler cannot tell. Let's not have bothersome warnings.
    private IEnumerable TreeViewOfInts = new ValueDropdownList<int>() {
        { "Node 1/Node 1.1", 1 },
        { "Node 1/Node 1.2", 2 },
        { "Node 2/Node 2.1", 3 },
        { "Node 3/Node 3.1", 4 },
        { "Node 3/Node 3.2", 5 },
        { "Node 1/Node 3.1/Node 3.1.1", 6 },
        { "Node 1/Node 3.1/Node 3.1.2", 7 },
    };

    private IEnumerable<MonoBehaviour> GetListOfMonoBehaviours() {
        return GameObject.FindObjectsOfType<MonoBehaviour>();
    }

    private static IEnumerable<KeyCode> KeyCodes = Enumerable.Range((int)KeyCode.Alpha0, 10).Cast<KeyCode>();

    private static IEnumerable GetAllSceneObjects() {
        Func<Transform, string> getPath = null;
        getPath = x => (x ? getPath(x.parent) + "/" + x.gameObject.name : "");
        return GameObject.FindObjectsOfType<GameObject>().Select(x => new ValueDropdownItem(getPath(x.transform), x));
    }

    private static IEnumerable GetAllScriptableObjects() {
        return UnityEditor.AssetDatabase.FindAssets("t:ScriptableObject")
                          .Select(x => UnityEditor.AssetDatabase.GUIDToAssetPath(x))
                          .Select(x => new ValueDropdownItem(x, UnityEditor.AssetDatabase.LoadAssetAtPath<ScriptableObject>(x)));
    }

    private static IEnumerable GetAllSirenixAssets() {
        var root = "Assets/Plugins/Sirenix/";

        return UnityEditor.AssetDatabase.GetAllAssetPaths()
                          .Where(x => x.StartsWith(root))
                          .Select(x => x.Substring(root.Length))
                          .Select(x => new ValueDropdownItem(x, UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(root + x)));
    }

    private static IEnumerable FriendlyTextureSizes = new ValueDropdownList<int>() {
        { "Small", 256 },
        { "Medium", 512 },
        { "Large", 1024 },
    };

    private static int[] TextureSizes = new int[] { 256, 512, 1024 };
#endif
}

相关推荐

  1. 2024-07-19 Unity Odin Serializer1 —— 介绍

    2024-07-15 13:26:02       20 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-15 13:26:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-15 13:26:02       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-15 13:26:02       58 阅读
  4. Python语言-面向对象

    2024-07-15 13:26:02       69 阅读

热门阅读

  1. 基于 kubeconfig 认证的 k8s 用户账号创建案列

    2024-07-15 13:26:02       23 阅读
  2. Oracle统计信息自动收集任务检查与调整

    2024-07-15 13:26:02       22 阅读
  3. 2024智慧竞技游戏俱乐部线下面临倒闭?

    2024-07-15 13:26:02       25 阅读
  4. Hypertable 自编译二进制包安装

    2024-07-15 13:26:02       28 阅读
  5. vue区分页面关闭和刷新(转)

    2024-07-15 13:26:02       25 阅读
  6. 线程池类的封装

    2024-07-15 13:26:02       26 阅读