OdinでInspectorのアイテム設定ウィンドウを見やすくする #2 [Odin][ScriptableObject][Unity][Inspector]

OdinでInspectorのアイテム設定ウィンドウを見やすくする #2

はじめに

インスペクタってデフォルトではこんな感じですが、
Odinという有料アセットを使うことで、表示をカスタマイズすることができます。

前回はこのように、変数をグループにまとめて見やすくしました。

今回は下記のようなリストを作成していきます!

リストの作成

今回はアイテムに属性がつけられる、ということを想定して作っていきます。
また、属性は属性値を持つようにします。

まず、元となる属性の種類をEnum型で定義します。

public enum ElementType
{
    Fire,
    Water,
    Wind,
    Earth
}

炎、水、風、土のイメージです。
次に属性値と属性を管理する構造体を作成します。

[Serializable]
public struct ElementValue
{
    public ElementType elementType;
    public int value;
}

ここから、前回まで作成したItemObjectに、このElementValue構造体のリストを持たせます。

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

#if UNITY_EDITOR
using Sirenix.Utilities;
#endif

[CreateAssetMenu(fileName="item", menuName="Item")]
public class ItemObject : ScriptableObject
{

    [HorizontalGroup("Split", LabelWidth=82)]
    [BoxGroup("Split/基本設定")]
    [HideLabel, PreviewField(64, ObjectFieldAlignment.Left)]
    public Sprite icon;

    [BoxGroup("Split/基本設定")]
    public string itemName;

    [BoxGroup("Split/基本設定")]
    public ItemType itemType;

    [VerticalGroup("Split/Right")]
    [BoxGroup("Split/Right/パラメータ")]
    public int rarity;
    [BoxGroup("Split/Right/パラメータ")]
    public int price;

    public List<ElementValue> elementList;
}

このように書いたら、一旦Unityのインスペクターを見ます。

Odin導入しているので、すでにデフォルトのリストより見やすくなっていますね!
凄いっ!!

でもここから更にOdinのDemoにあるように、見やすくカスタマイズしていきます。

追加ボタンを押した時の動作をカスタマイズ

属性値は同じものを何度もつける必要はありませんよね?
効果を増幅させたければ、数値を大きくすればいいのです。

ということで、属性は追加するときにだけ選ぶようにします。
また、重複しないようにリストの追加はチェックボックス式にします。

上の図のようにしていきます。
これならば、重複もすることなく、
しかも属性を選ぶ場所が省けるので、見た目がスッキリします。

ドロップダウンメニューの作成

まずは、リストへの追加をドロップダウンメニューで選択できるようにします。

[ValueDropdown("CustomAddElementButton", IsUniqueList = true, DrawDropdownForListElements = false, DropdownTitle = "Element")]
public List<ElementValue> elementList;

リストの上にValueDropdown Attributeをつけました。
最初の引数は何を対象とするかのメソッド名で、これから定義します。

#if UNITY_EDITOR
private IEnumerable CustomAddElementButton()
{
    return Enum.GetValues(typeof(ElementType)).Cast<ElementType>()
    .Except(elementList.Select(x => x.elementType))
    .Select(x => new ElementValue(x))
    .AppendWith(elementList)
    .Select(x => new ValueDropdownItem(x.elementType.ToString(), x));
}
#endif

returnされるものを順番に見ていきましょう。

  1. GetValues

    GetValues(typeof(ElementType)).Cast<ElementType>()

    では、ElementType型について取得しています。

  2. Except

    Except(elementList.Select(x => x.elementType)

    では、ドロップダウンリストのチェックマークとElementTypeの差集合
    つまり、チェックマークがついていないものについて取得されています。

  3. Select

    Select(x => new ElementValue(x))

    ここは取得したもので、ElementValueを作成します。
    これはコンストラクタを呼び出していて、
    後ほど、ElemetValueのコンストラクタを作成します。

  4. AppendWith

    AppendWith(elementList)

    これはusing Sirenix.Utilities;で使用可能になるメソッドで、
    (おそらく)ドロップダウンリストでチェックマークが押された際に
    追加するものを取得しておく処理であると思われます。

  5. Select

    Select(x => new ValueDropdownItem(x.elementType.ToString(), x));

    ここで、ドロップダウンリストに取得したものが追加されます。
    取得していたのはチェックマークがついていないものなので、
    それらが追加されます。

(img)

動作を確認すると、チェックマークがついてものが下に配置されているので、そんな感じではないでしょうか。
どこかで、チェックマークついたものの処理があるのでしょうか。

ちょっと色々と怪しいので、
間違っていたり、気づいたことがあれば教えてください。

ElemetValueのコンストラクタの定義

先ほど追加した際に呼び出したコンストラクタを定義しておきます。
ついでに、ElementTypeは選択できないようにしておきます。
また、属性値のラベルに選択されたelementTypeが表示されるようにします。

[Serializable]
public struct ElementValue
{
    [HideInInspector]
    public ElementType elementType;

    [LabelText("$elementType")]
    public int value;

    // インスペクタでの追加時に呼び出されるコンストラクタ
    public ElementValue(ElementType type)
    {
        elementType = type;
        value = 0;
    }
}

ここまで実装すると、インスペクタは以下のように動作します。

2行が1行になり、見やすくなりましたね!

終わりに

あっさりといい感じのリストが出来上がりました。
使いこなせるかは分からないけど、ほんと便利ですね。

もっと日本語の情報が増えてほしいです!
そのためにも自分でまずは発信していきますね!

また次回も色々と触っていきます!

コメント

タイトルとURLをコピーしました