【Unity】属性を用いたエディタ拡張を提供する「Lucid Editor」を公開しました

UnityのInspectorを拡張する属性を追加するライブラリ「Lucid Editor」を公開しました。

 

例によって使い方はREADMEやwikiに全て記載されているので、ここでは技術的な詳細やらなんやらを語っていきます。

Lucid Editorとは

「Lucid Editor」は、Inspectorの表示をカスタマイズする30種類の属性を追加するライブラリです。本当は他にもいろんな機能があるんですが、とりあえずここでは省略。

では試しに、BoxGroupAttributeを追加してみましょう。
using UnityEngine;
using AnnulusGames.LucidTools.Inspector;

public class AttributeExample : MonoBehaviour
{
     [BoxGroup("Group")] public int foo;
     [BoxGroup("Group")] public string bar;
     [BoxGroup("Group")] public float baz;
     [BoxGroup("Group")] public Vector3 qux;
}

こんな感じで、属性を追加するだけでフィールドの表示をグループ化することが可能です。

他にも、ヘッダーやタブの追加や値の検証、条件による表示の切り替えなど、より複雑なカスタマイズを属性だけで行うことが可能です。


内部の実装について

では、このLucid Editorがどのような仕組みで動いているのかについてを簡単に説明していきます。

まず、UnityでInspectorの表示をカスタマイズする手段について考えてみます。アセットなどを利用しない限り、基本的には以下の二つのうちどちらかの方法を利用することになるでしょう。

・対象のMonoBehaviourやScriptableObjectに対応したEditorクラスを実装

・対象のクラスや属性に対応したPropertyDrawerを実装


このうち「属性によるエディタ拡張」と聞いてまず思い浮かべるのは、PropertyDrawerを用いた実装の方法です。例えば、Inspectorのフィールドを編集不可にする「ReadOnlyAttribute」をPropertyDrawerを用いて実装してみます。

using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
public class ReadOnlyDrawer : PropertyDrawer
{
    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginDisabledGroup(true);
        EditorGUI.PropertyField (position, property, label);
        EditorGUI.EndDisabledGroup();
    }
}

こんな感じでしょうか。

このぐらいの単純な属性であればPropertyDrawerだけでも十分実装が可能です。では、先ほどのBoxGroupAttributeのような、グループ化を行う属性を作るにはどうしたら良いでしょうか。

不可能ではないかもしれませんが、PropertyDrawerだけでこれを行うのは非常に難しいでしょう。正直、この方法では実装が全く思い浮かびませんでした。

さらに、PropertyDrawerを複数追加すると、競合を起こして表示がおかしくなることがあります。多数の属性を付加することが前提である以上、PropertyDrawerを用いるのであれば、この問題も解決しなければなりません。


当然、Lucid EditorではPropertyDrawerは一切使われていません。では、PropertyDrawerなしでどうやって実装していけば良いのか。


答えは簡単です。先ほどの二つの方法のうち、もう一つの方法を使います。すなわち、

・対象のMonoBehaviourやScriptableObjectに対応したEditorクラスを実装

することです。

自作のEditorクラスを実装する際、対象のクラスを指定するためにCustomEditor属性を追加しますが、この属性には二つ目の引数にbool型を指定できます。

[CustomEditor(typeof(TargetBehaviour), editorForChildClasses: true)]

これは対象のクラスの子クラスにカスタムエディタを適用するかを設定するもので、デフォルトではfalseに設定されています。


お分かりでしょうか。要するに、Lucid EditorはMonoBehaviour及びScriptableObjectを対象としたEditorクラスを提供します。よって、Lucid Editorを導入すると、自作した全てのクラスのInspectorが独自のEditorによって描画されることになるのです。

また、属性の描画にはPropertyProcessorクラスを利用します。このクラスが描画の前後に独自の処理を差し込むことで、複雑なInspectorの拡張を実現しています。

using UnityEditor;
using AnnulusGames.LucidTools.Inspector;

namespace AnnulusGames.LucidTools.Editor
{
    [CustomAttributeProcessor(typeof(ReadOnlyAttribute))]
    public class ReadOnlyAttributeProcessor : PropertyProcessor
    {
        public override void OnBeforeDrawProperty()
        {
            property.isEditable = false;
        }
    }
}

こちらがPropertyProcessorを利用したReadOnlyAttributeの実装です。
InspectorPropertyという型で情報を受け取り、それを書き換えることで表示方法をカスタマイズしています。


最後に

今回のLucid Editorはぶっちゃけ「Odinがないなら自分で作ればいいじゃない」の精神で作ったオレオレライブラリなんですが、その割にはそれなりに使いやすく、機能的なものが出来上がったのではないでしょうか。

機能性では敵いませんが、こちらはオープンソースでライセンスもゆるゆるなので「Odin持ってないけど手軽にInspectorの拡張をしたい」という方にはぜひ、この「Lucid Editor」を使ってみてもらえると嬉しいです。

まだリリースしたてで不具合が残っている可能性も大いにありますので、もし何かあれば教えてもらえると助かります!


コメント