Unityプラグイン Odin Inspector2 —— 必須属性

1 説明

​ 本稿では Odin Inspector プラグインの重要な機能の使用方法を紹介します。

2 重要機能

2.1 AssetsOnly / SceneObjectsOnly

ターゲットオブジェクトが Inspector ウィンドウでリソース/シーンオブジェクトのみに関連付けられるようにし、ドラッグ可能なリソースタイプを制限します。

// SceneAndAssetsOnlyExamplesComponent.cs

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

public class SceneAndAssetsOnlyExamplesComponent : MonoBehaviour
{
    [Title("リソースのみ")]
    [AssetsOnly]
    public List<GameObject> PrefabsOnly;

    [AssetsOnly]
    public GameObject SinglePrefab;

    [AssetsOnly]
    public Material MaterialAsset;

    [AssetsOnly]
    public MeshRenderer MeshRendererOnPrefab;

    [Title("シーンオブジェクトのみ")]
    [SceneObjectsOnly]
    public List<GameObject> SceneObjectsOnly;

    [SceneObjectsOnly]
    public GameObject SingleSceneObject;

    [SceneObjectsOnly]
    public MeshRenderer SceneMeshRenderer;
}

2.2 CustomValueDrawer

カスタム属性の表示方法を定義します。

  • string action

    属性の表示方法名。

  1. action メソッド内に GUI 表示ロジックを記述し、フィールドの値を返します。
  2. この属性が配列に適用されると、配列の各要素に一度適用されます。
  3. この属性を使用する場合、UNITY_EDITOR ディレクティブと組み合わせる必要があります。
// CustomValueDrawerExamplesComponent.cs

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

#if UNITY_EDITOR // エディタ名前空間はエディタでのみ使用可能です。
using Sirenix.Utilities.Editor;
using UnityEditor;
#endif

public class CustomValueDrawerExamplesComponent : MonoBehaviour
{
    public float MinValue = 2, MaxValue = 7;

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

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

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

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

#if UNITY_EDITOR // ビルドからエディタ関連コードを除外
    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.MinValue, this.MaxValue);
    }

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

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

2.3 OnValueChanged

Inspector で属性を編集する際に、属性への変更を遅延適用します。値を変更すると、適用されません(黄色表示)。変更が完了した後にのみ、その値が適用されます。

Unity の組み込み遅延属性に似ていますが、この属性はプロパティにも適用できます。

// DelayedPropertyExampleComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class DelayedPropertyExampleComponent : MonoBehaviour
{
    // Delayed と DelayedProperty 属性はほぼ同一です...
    [Delayed]
    [OnValueChanged("OnValueChanged")]
    public int DelayedField;

    // ...しかし DelayedProperty は、名前が示すように、プロパティにも適用できます。
    [ShowInInspector, DelayedProperty]
    [OnValueChanged("OnValueChanged")]
    public string DelayedProperty { get; set; }

    private void OnValueChanged() {
        Debug.Log("値が変更されました!");
    }
}

2.4 DetailedInfoBox

属性にメッセージボックスを設定します。

  • string message

    デフォルトで表示される情報。

  • string details

    クリック後に展開して表示される詳細情報。

  • InfoMessageType infoMessageType = InfoMessageType.Info

    メッセージボックスの種類。

  • string visibleIf = null

    式が true の場合に表示し、そうでない場合は表示しません。

// DetailedInfoBoxExampleComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class DetailedInfoBoxExampleComponent : MonoBehaviour
{
    [DetailedInfoBox("DetailedInfoBox をクリックしてください...",
        "...より多くの情報を表示します!\n" +
        "これにより、エディタの不要なクラッタを減らし、必要なときにすべての関連情報を利用できます。")]
    public int Field;
}

2.5 EnableGUI

GUI インタラクションを有効にし、Inspector ウィンドウで編集できるようにします。

// EnableGUIExampleComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

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

2.6 GUIColor

GUI に色を適用します。

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

    RGBA で色を指定します。

  • string getColor

    色名を指定します。

// 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 ApplyAction() { }

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

    [InfoBox("ボタンの色を動的に変更するために、色メンバーを参照することもできます。")]
    [GUIColor("GetButtonColor")]
    [Button("素晴らしいです", ButtonSizes.Gigantic)]
    private static void FabulousAction() { }

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

#if UNITY_EDITOR // ビルドからエディタ関連コードを除外
    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

属性名を非表示にします。

// HideLabelExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class HideLabelExamplesComponent : MonoBehaviour
{
    [Title("広い色")]
    [HideLabel]
    [ColorPalette("Fall")]
    public Color WideColor1;

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

    [Title("広いベクトル")]
    [HideLabel]
    public Vector3 WideVector1;

    [HideLabel]
    public Vector4 WideVector2;

    [Title("広い文字列")]
    [HideLabel]
    public string WideString;

    [Title("広い複数行テキストフィールド")]
    [HideLabel]
    [MultiLineProperty]
    public string WideMultilineTextField = "";
}

2.8 PropertyOrder

属性の表示順序を指定します。

  • float order

    表示順序、小さい順に並べます。

// PropertyOrderExamplesComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class PropertyOrderExamplesComponent : MonoBehaviour
{
    [PropertyOrder(1)]
    public int SecondField;
    
    [InfoBox("PropertyOrder は Inspector でのプロパティの順序を変更するために使用されます。")]
    [PropertyOrder(-1)]
    public int FirstField;
}

2.9 PropertySpace

属性の表示間隔を指定します。

  • float spaceBefore

    上の間隔。

  • float spaceAfter

    下の間隔。

// SpaceExampleComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class SpaceExampleComponent : MonoBehaviour
{
    // PropertySpace と Space 属性はほぼ同一です。
    [Space]
    [BoxGroup("Space", ShowLabel = false)]
    public int SpaceField;
    
    // PropertySpace 属性の前後の間隔を制御することもできます。
    [PropertySpace(SpaceBefore = 30, SpaceAfter = 60)]
    [BoxGroup("BeforeAndAfter", ShowLabel = false)]
    public int BeforeAndAfterField;
    
    // PropertySpace 属性は、名前が示すように、プロパティにも適用できます。
    [PropertySpace]
    [ShowInInspector, BoxGroup("Property", ShowLabel = false)]
    public string Property { get; set; }
}

2.10 ReadOnly

Inspector ウィンドウで表示のみで、値を変更できないようにします。

// ReadOnlyExamplesComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class ReadOnlyExamplesComponent : MonoBehaviour
{
    [ReadOnly]
    public string DisplayedString = "これはテキストとして表示されます";

    [ReadOnly]
    public int DisplayedInt = 9001;
    
    [ReadOnly]
    public int[] DisplayedIntList = new int[] { 1, 2, 3, 4, 5, 6, 7, };
}

2.11 Required

オブジェクトに関連付けられた値がない場合、メッセージを表示します。

  • string errorMessage

    表示するメッセージ。

  • InfoMessageType messageType

    メッセージの種類。

// RequiredExamplesComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class RequiredExamplesComponent : MonoBehaviour
{
    [Required]
    public GameObject TargetGameObject;
    
    [Required("カスタムエラーメッセージ。")]
    public Rigidbody TargetRigidbody;
    
    [InfoBox("メンバー文字列をメッセージとして使用するには $ を使用します。")]
    [Required("$DynamicMessage")]
    public GameObject DynamicGameObject;
    
    public string DynamicMessage = "動的なエラーメッセージ";
}

2.12 RequiredIn

このオブジェクトが属するスクリプトがどのプレハブにアタッチされている場合、修飾されたオブジェクトが関連付けられていない場合にエラーメッセージを表示します。

  • string errorMessage

    表示するメッセージ。

  • PrefabKind prefabKind

    プレハブの種類。

    1. None

      すべてのプレハブが条件を満たしません。

    2. InstanceInScene

      シーン内のプレハブインスタンス。

    3. InstanceInPrefab

      他のプレハブ内にネストされたプレハブインスタンス。

    4. Regular

      通常のプレハブ。

    5. Variant

      プレハブアセット。

    6. NonPrefabInstance

      プレハブ以外またはシーン内のゲームオブジェクトインスタンス。

    7. PrefabInstance = InstanceInPrefab | InstanceInScene

      通常のプレハブインスタンス、およびシーン内または他のプレハブ内にネストされたプレハブ。

    8. PrefabAsset = Variant | Regular

      通常のプレハブとプレハブアセット。

    9. PrefabInstanceAndNonPrefabInstance = PrefabInstance | NonPrefabInstance

      プレハブおよびプレハブ以外のインスタンス。

    10. All = PrefabInstanceAndNonPrefabInstance | PrefabAsset

      すべてのプレハブ。

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

public class Test : MonoBehaviour
{
    [RequiredIn(PrefabKind.PrefabAsset)]
    public GameObject TargetObject;
}

2.13 Searchable

子要素のタイプと名前を検索できます。

  • bool FuzzySearch = true

    検索にあいまい文字列マッチングを使用するかどうか。

  • SearchFilterOptions FilterOptions = SearchFilterOptions.All

    検索方法。

  • bool Recursive = true

    再帰的に検索するか、トップレベルの属性のみを検索するか。

// 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 はメンバーをシリアル化せず、この属性のみを使用しても変更は保存されません。

// 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

    タイトルを太字で表示するかどうか。

// TitleExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class TitleExamplesComponent : MonoBehaviour
{
    [Title("タイトルとヘッダー")]
    public string MyTitle = "動的なタイトル";

    public string MySubtitle = "動的なサブタイトル";

    [Title("静的なタイトル")]
    public int C;

    public int D;

    [Title("静的なタイトル", "静的なサブタイトル")]
    public int E;

    public int F;

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

    public int H;

    [Title("太字ではないタイトル", "$MySubtitle", bold: false)]
    public int I;

    public int J;

    [Title("太字ではないタイトル", "区切り線なし", 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("プロパティのタイトル")]
    public int S { get; set; }

    [Title("メソッドのタイトル")]
    [Button]
    public void DoNothing() { }
}

2.16 TypeFilter

タイプに基づいて属性を表示します。

  • string filterGetter

    表示する属性を取得するメソッド。

// 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)                                          // BaseClass を除外
            .Where(x => !x.IsGenericTypeDefinition)                             // C1<> を除外
            .Where(x => typeof(BaseClass).IsAssignableFrom(x));                 // BaseClass を継承しないクラスを除外
    
        // さまざまな C1<T> 型バリアントを追加します。
        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

    描画する情報。

// TypeInfoBoxExampleComponent.cs

using Sirenix.OdinInspector;
using System;
using UnityEngine;

#if UNITY_EDITOR // エディタ名前空間はエディタでのみ使用可能です。
using Sirenix.OdinInspector.Editor.Examples;
#endif

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

#if UNITY_EDITOR // MyScriptyScriptableObject は例示タイプであり、エディタでのみ存在します
    [InfoBox("ペンアイコンをクリックして Scripty オブジェクトの新しいインスペクターを開きます。")]
    [InlineEditor]
    public MyScriptyScriptableObject Scripty;
#endif

    [Serializable]
    [TypeInfoBox("TypeInfoBox 属性は型定義に配置でき、結果としてプロパティの上部に InfoBox が描画されます。")]
    public class MyType
    {
        public int Value;
    }

#if UNITY_EDITOR // ビルドからエディタ関連コードを除外
    [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

    メッセージの種類。

// ValidateInputExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

#if UNITY_EDITOR // エディタ名前空間はエディタでのみ使用可能です。
using Sirenix.OdinInspector.Editor.Examples;
#endif

public class ValidateInputExamplesComponent : MonoBehaviour
{
#if UNITY_EDITOR // MyScriptyScriptableObject は例示タイプであり、エディタでのみ存在します
    [HideLabel]
    [Title("デフォルトメッセージ", "デフォルトメッセージを常に使用するだけです")]
    [ValidateInput("MustBeNull", "このフィールドは null である必要があります。")]
    public MyScriptyScriptableObject DefaultMessage;
#endif

    [Space(12), HideLabel]
    [Title("動的メッセージ", "または検証メソッドはカスタムメッセージを動的に提供できます")]
    [ValidateInput("HasMeshRendererDynamicMessage", "プレハブには MeshRenderer コンポーネントが必要です")]
    public GameObject DynamicMessage;

    [Space(12), HideLabel]
    [Title("動的メッセージタイプ", "検証メソッドはメッセージの種類も制御できます")]
    [ValidateInput("HasMeshRendererDynamicMessageAndType", "プレハブには MeshRenderer コンポーネントが必要です")]
    public GameObject DynamicMessageAndType;

    [Space(8), HideLabel]
    [InfoBox("GameObject 値を変更してメッセージタイプを更新", InfoMessageType.None)]
    public InfoMessageType MessageType;

    [Space(12), HideLabel]
    [Title("動的デフォルトメッセージ", "メンバー文字列をデフォルトメッセージとして使用するには $ を使用します")]
    [ValidateInput("AlwaysFalse", "$Message", InfoMessageType.Warning)]
    public string Message = "動的な ValidateInput メッセージ";

#if UNITY_EDITOR // ビルドからエディタ関連コードを除外
    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) {
            // errorMessage が null のままの場合、属性からのデフォルトエラーメッセージが使用されます
            errorMessage = "\"" + gameObject.name + "\" には MeshRenderer コンポーネントが必要です";

            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) {
            // errorMessage が null のままの場合、属性からのデフォルトエラーメッセージが使用されます
            errorMessage = "\"" + gameObject.name + "\" には MeshRenderer コンポーネントが必要です";

            // messageType が null のままの場合、属性からのデフォルトメッセージタイプが使用されます
            messageType = this.MessageType;

            return false;
        }

        return true;
    }
#endif
}

2.19 ValueDropdown

Inspector パネルで対応する値を選択するためのドロップダウンリストを作成します。

  • string valuesGetter

    ドロップダウンリストの選択可能な値を取得するメソッド。戻り値は配列または ValueDropdownList の 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 の場合、この属性を有効にすると既存の値が除外されます。

    それ以外の場合、項目が含まれているかどうかを示すチェックボックスが表示されます。

// 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 = "シーンオブジェクトを選択", DrawDropdownForListElements = false, ExcludeExistingValuesInList = true)]
    public List<GameObject> UniqueGameobjectListMode2;

#if UNITY_EDITOR        // ビルドからエディタ関連コードを除外
#pragma warning disable // これらのメンバーは実際には使用されていますが、コンパイラは知りません。面倒な警告を避けましょう。
    private IEnumerable TreeViewOfInts = new ValueDropdownList<int>() {
        { "ノード 1/ノード 1.1", 1 },
        { "ノード 1/ノード 1.2", 2 },
        { "ノード 2/ノード 2.1", 3 },
        { "ノード 3/ノード 3.1", 4 },
        { "ノード 3/ノード 3.2", 5 },
        { "ノード 1/ノード 3.1/ノード 3.1.1", 6 },
        { "ノード 1/ノード 3.1/ノード 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>() {
        { "小", 256 },
        { "中", 512 },
        { "大", 1024 },
    };

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

タグ: Unity Odin Inspector C# ゲーム開発 Inspector拡張

5月20日 13:32 投稿