ひつじTips

技術系いろいろつまみ食います。

[Unity]CustomEditorを使わずに,同じクラスの他の変数の状態によってインスペクタ上の変数を動的に編集不可にしたり,非表示にしたりする方法

こちらの記事ではbool型変数によって,変数の編集可/不可・表示/非表示を制御していました

mu-777.hatenablog.com

が,本記事ではそれの拡張版で,int/enum,string,float型の変数によっても制御できるようにします.

(本記事だけで内容は完結してますので,前記事を事前に読む必要はありません)

つまり何ができるか,ということですが,

例えばこういう実装で

public class ConditionalDisableAttrTest : MonoBehaviour
{
    public enum FlagEnum { A, B, C }
    [Header("Enum control")]
    public FlagEnum flagEnum = FlagEnum.A;

    [ConditionalDisableInInspector("flagEnum", (int)FlagEnum.A)]
    public string editableStrIfEnumA = "AAA";

    [ConditionalDisableInInspector("flagEnum", (int)FlagEnum.B)]
    public string editableStrIfEnumB = "BBB";

    [ConditionalDisableInInspector("flagEnum", (int)FlagEnum.C)]
    public string editableStrIfEnumC = "CCC";
}


こういう感じに編集可/不可を制御できたり,

simple enum conditional control in inspector
FlagEnumの設定値によって,他の変数の編集可/不可を制御できる

こうすれば,

public class ConditionalDisableAttrTest : MonoBehaviour
{
    [System.Serializable]
    public struct TestStruct
    {
        public Vector3 p;
        public Quaternion q;
    }

    [Header("String control")]
    public string flagStr = "A";

    [ConditionalDisableInInspector("flagStr", "A", conditionalInvisible: true)]
    public TestStruct visibleStructIfA;
}


表示/非表示を制御できたりします.(自作クラス/構造体も可)

simple string conditional control in inspector
flagStrが”A”のときだけインスペクタに表示される


こういうことをしたくて「Unity インスペクタ 変数 動的」とかでググると,CustomEditorを使う方法が出てきます.

が,これだとCustomEditorで対応したクラスでしか使えない = 他のクラスの変数に使い回しができなくて,ちょろっと使いたいときに不便な感じです.

(プロダクトレベルとかで,しっかり作り込む場合はこちらの方がいいと思いますが)

ということで,今回はCustomEditorは使わずに,任意のクラスの変数に適用できるAttributeを使って実装しています.

正直Unityのエディタ拡張は全然詳しくないので,バグってたらすみません.
一通りの型で使えることは確認しましたが,漏れもあるだろうし,基本正常系しか確認できてません.他のAttributeとの組合せ時とかも未検証です(免責事項)


あまり複雑な実装はいらない,以下のようにシンプルにbool変数で制御するだけでよい,という方は,前記事をご覧ください

編集可/不可 表示/非表示
flag conditional control in inspector
flagがfalseのときは編集不可になる
flagがfalseのときはインスペクタから見えなくなる

使い方

まず,AttributeとEditor拡張のクラスを用意します.その後,編集不可にしたり非表示にしたい変数に対してAttributeをつけます.

というだけです.順番に見ていきます.

AttributeとEditor拡張のクラスの作成

以下に貼ったコードのファイルを作成します.

1つ目(ConditionalDisableDrawer.cs)をEditorフォルダに,2つ目(ConditionalDisableInInspectorAttribute.cs)は普通にScriptフォルダに,スクリプトファイルを作ってください.

gist77dd59ad1c764387ec5fca3c185e04c2

これで準備OKです.

アトリビュートの利用方法(int)

あとは,任意のMonoBehaviourなクラスの,インスペクタ上の表示制御したい変数にConditionalDisableInInspectorアトリビュートをつけて,第一引数に制御用変数の変数名をstringで,第二引数に比較対象の値を設定してください.

制御用変数がintのとき,具体的には以下のようにします.

    public int flagInt = 1;

    [ConditionalDisableInInspector("flagInt", 1)]
    public string editableStrIf1;

第一引数の文字列(この例だと"flagInt")が示す変数(flagInt)が,第二引数(この例だと1)と同じときに編集可に,flagInt1ではないときに編集不可になります.

int simple conditional control in inspector
flagIntが1だとeditableStrIf1が編集可に,それ以外だと編集不可になっている

(もちろん第二引数の比較対象は1以外でも大丈夫です.利用状況によって設定してください)


逆にしたい場合,つまりflagInt1ではないときに編集可にしたい場合は,notEqualThenEnableを明示的にtrueにしてください.

    [ConditionalDisableInInspector("flagInt", 1, notEqualThenEnable: true)]
    public Gradient editableGradUnless1;


また,編集可/不可ではなく,表示/非表示を制御したい場合はconditionalInvisibleをtrueにしてください.notEqualThenEnableと併用も可能です.

    [ConditionalDisableInInspector("flagInt", 1, conditionalInvisible: true)]
    public Color visibleColorIf1;

    [ConditionalDisableInInspector("flagInt", 1, notEqualThenEnable: true, conditionalInvisible: true)]
    public Bounds visibleBoundsUnless1;


すべて合わせると,以下のようになります.

int conditional control in inspector
flagIntが1だと編集できたりできなかったり,表示されたりされなかったり

アトリビュートの利用方法(enum

int型で制御できるので,つまりenumでも制御が可能です.

以下のように,第一引数をenumの変数名"flagEnum",第二引数を比較したいenumをintにキャストして入れてください.

    // ---------
    public enum FlagEnum { A, B, C }
    public FlagEnum flagEnum = FlagEnum.A;

    [ConditionalDisableInInspector("flagEnum", (int)FlagEnum.A, conditionalInvisible: true)]
    public string visibleStrIfEnumA = "A";

    [ConditionalDisableInInspector("flagEnum", (int)FlagEnum.B, conditionalInvisible: true)]
    public string visibleStrIfEnumB = "B";

    [ConditionalDisableInInspector("flagEnum", (int)FlagEnum.C, conditionalInvisible: true)]
    public string visibleStrIfEnumC = "C";


このとき,Inspector上では以下のような挙動になります.

enum conditional control in inspector
flagEnumの設定値によって,表示される変数が変わっている

この例では使っていないですが,intと同様にnotEqualThenEnableも使えます.

アトリビュートの利用方法(string)

string型の変数によって他の変数の編集不可・非表示を扱うためには,以下のように,ConditionalDisableInInspectorアトリビュートをつけて,第一引数に制御用変数(string)の変数名をstringで,第二引数に比較対象の文字列を設定してください.

制御用変数(この例ではflagStr)が,第二引数の文字列(この例では"A")と同じであれば編集可,異なれば編集不可になります.

    public string flagStr = "A";

    [ConditionalDisableInInspector("flagStr", "A")]
    public AnimationCurve editableAminCurveIfA;


逆にしたい場合,つまりflagStrが"A”と異なる場合に編集可にしたい場合は,notEqualThenEnableをtrueに設定してください.

    [ConditionalDisableInInspector("flagStr", "A", notEqualThenEnable: true)]
    public Vector2 editableVec2UnlessA;


編集可/不可ではなく,表示/非表示を制御したい場合はconditionalInvisibleをtrueに設定してください.notEqualThenEnableと併用も可能です.

    [ConditionalDisableInInspector("flagStr", "A", conditionalInvisible: true)]
    public Quaternion visibleQuatIfA;

    [ConditionalDisableInInspector("flagStr", "A", notEqualThenEnable: true, conditionalInvisible: true)]
    public int visibleIntUnlessA;

すべて合わせると,以下のようになります.

str conditional control in inspector
flagStrの値によって,編集できたりできなかったり,表示されたりされなかったり

アトリビュートの利用方法(float)

int(enum),stringに続き,float型変数での編集不可・非表示制御の方法です.

float型でも同様に,ConditionalDisableInInspectorアトリビュートをつけて,第一引数に制御用変数(string)の変数名をstringで,第二引数に比較対象のfloat値を設定してください.

    public float flagFloat = 0f;

    [ConditionalDisableInInspector("flagFloat", 0f)]
    public GameObject editableGameObjIfOver0;

int(enum),stringでの制御と異なり,このとき,flagFloatが第二引数(ここでは0f)より大きければ編集可に,小さければ編集不可になります.


挙動を逆にしたい場合,flagFloatが第二引数の0fより小さいときに編集可にしたい場合は,greaterThanComparedThenEnableをfalseに設定してください.

    [ConditionalDisableInInspector("flagFloat", 0f, greaterThanComparedThenEnable: false)]
    public FlagEnum editableEnumIfUnder0Or0;


また,編集可/不可ではなく表示/非表示にしたい場合は,他と同じくconditionalInvisibleをtrueにしてください.

    [ConditionalDisableInInspector("flagFloat", 0f, conditionalInvisible: true)]
    public List<float> invisibleListIfOver0;

    [ConditionalDisableInInspector("flagFloat", 0f, greaterThanComparedThenEnable: false, conditionalInvisible: true)]
    public Vector3 invisibleVec3IfUnder0Or0;


すべて合わせると,こんな感じです.

float conditional control in inspector
flagFloatの値が0より大きいかどうかで,他の変数が編集不可になったり,非表示になったり

アトリビュートの利用方法(bool)

もちろんbool変数でも制御可能です.

ConditionalDisableInInspectorアトリビュートをつけて,第一引数に制御用bool変数の変数名をstringで指定してください.

    public bool flag = false;

    [ConditionalDisableInInspector("flag")]
    public string editableStrIfTrue = "a";


挙動を逆にしたい場合,つまり,flagがfalseのときに編集可にしたい場合は,AttributeのtrueThenDisable引数をtrueに設定してください.

    [ConditionalDisableInInspector("flag", trueThenDisable: true)]
    public Rect editableRectIfFalse;


また,編集可/不可ではなく,表示/非表示を切り替えたい場合は,conditionalInvisibleをtrueに設定してください.trueThenDisableも併用可能です.

    [ConditionalDisableInInspector("flag", conditionalInvisible: true)]
    public float visibleFloatIfTrue = 0f;

    [ConditionalDisableInInspector("flag", trueThenDisable: true, conditionalInvisible: true)]
    public Vector3 visibleVec3IfFalse;


この4つを並べると,以下のようになると思います.

flag conditional control in inspector
flag変数の状態によって,各変数の表示が編集できたりできなかったり,表示されたりされなかったり

簡単な解説

実装的な実現方法については,前記事と同じなのでこちらの「簡単な解説」を参照ください

mu-777.hatenablog.com

最後に

とりあえず実装しちゃいましたが,floatで制御したいときってどういうときか自分でもよくわからんですね笑

boolはもちろん,int, enum, stringまではありそうですが,float制御の有益な利用の仕方があれば教えてくださいw