はじめに
UI Toolkit(UIElements)でUI作ってたら CustomEditor
属性に便利なフラグを見つけたので紹介します。
環境
- Unity2021.3.0f1
背景と問題点
背景
「IMGUIはもう嫌だ!俺はUI ToolkitでUIを作るんだ!」となってカスタム PropertyDrawer
を書いたとします。
試しに以下のようなコンポーネントと、UI Toolkit(というか VisualElement
)を使って描画する PropertyDrawer
を実装してみます。
using System;
using UnityEngine;
public class SampleComponent : MonoBehaviour
{
public SampleClassWithIMGUI sampleClassWithIMGUI;
public SampleClassWithUIToolkit sampleClassWithUIToolkit;
}
[Serializable]
public class SampleClassWithIMGUI
{
public bool isUIToolkit = false;
}
[Serializable]
public class SampleClassWithUIToolkit
{
public bool isUIToolkit = true;
}
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
[CustomPropertyDrawer(typeof(SampleClassWithUIToolkit))]
public class SampleClassWithUIToolkitPropertyDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
return new PropertyField(property)
{
// 色を赤くしてみる
style = { color = new StyleColor(Color.red) },
};
}
}
#endif
上記の SampleComponent
を適当な GameObject
につけると、Inspectorはこうなります。
IMGUIで描画されるクラス SampleClassWithIMGUI
は通常通り描画されてますが、UI Toolkitで描画したい SampleClassWithUIToolkit
クラスは謎の "No GUI Implemented" というメッセージが出るだけで描画されてません。
これはフォーラムの投稿によると
That is, you need to make sure to override CreateInspectorGUI() on the Editor class for your object and then populate manually with PropertyFields. This is a temporary situation until we switch the default inspectors of all objects to UIElements (right now default inspectors still use IMGUI).
つまり、オブジェクトのEditorクラスでCreateInspectorGUI()をオーバーライドし、PropertyFieldsを手動で入力する必要があります。これは、すべてのオブジェクトのデフォルトインスペクタをUIElementsに切り替えるまでの一時的な状況です(現在、デフォルトインスペクタはまだIMGUIを使用しています)。
(DeepL翻訳)
だからだそうで、 SampleComponent
のカスタム Editor
を実装すればOKです。
// 参考:
// https://issuetracker.unity3d.com/issues/propertydrawer-dot-createpropertygui-will-not-get-called-when-using-a-custompropertydrawer-with-a-generic-struct
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
[CustomEditor(typeof(SampleComponent))]
public class SampleComponentEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
var container = new VisualElement();
// IMGUI同様のInspectorを実装
InspectorElement.FillDefaultInspector(container, serializedObject, this);
return container;
}
}
#endif
これでUI Toolkitでも描画されるようになりました。めでたしめでたし。
問題点
すでにお気づきかと思われますが、これだと
「UI Toolkitでカスタムプロパティドロワーを実装したら、その対象クラスを使用するクラスは必ずカスタムエディタを書かないといけない」
ということになってしまいます(正気か!?)。
この問題の解決方法として、先に上げた SampleComponentEditor
のような汎用クラスを作って「これを継承すればカスタム Editor
を数行で実装できる」というのを見たのですが、もっとスマートな方法があったので紹介します。
CustomEditor
の isFallback
フラグ
解決方法は以下のカスタム Editor
を一つ追加するだけです。
SampleComponentEditor
みたいな個別のカスタム Editor
は必要ありません。
// 参考URL:
// https://forum.unity.com/threads/property-drawers.595369/#post-5118800
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
[CustomEditor(typeof(Object), true, isFallback = true)]
public class DefaultEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
var container = new VisualElement();
// IMGUI同様のInspectorを実装
InspectorElement.FillDefaultInspector(container, serializedObject, this);
return container;
}
}
#endif
CustomEditor
の isFallback
というフラグを true
にすると
「他に適用されるカスタム Editor
が存在しない場合のデフォルト Editor
」
として使用されます。
以下は ドキュメント からの引用です。
CustomEditor.isFallback
public bool isFallback;
Description
If true, match this editor only if all non-fallback editors do not match. Defaults to false.Unity does a two-pass match to hook up editors with inspected types. First the non-fallback editors are tested, and if none match, then the fallbacks are tested for a match. Setting this flag lets you set up a default editor for a given type, while still permitting another editor type to override it.
trueの場合、フォールバックしないエディタがすべてマッチしない場合にのみ、このエディタをマッチさせます。デフォルトはfalseです。
Unityは、検査されたタイプのエディタをフックするために、2パスマッチを行います。まず、フォールバックでないエディタがテストされ、マッチするものがなければ、フォールバックがマッチするかどうかテストされます。このフラグを設定することで、特定のタイプのデフォルトエディタを設定することができ、同時に他のエディタタイプによるオーバーライドを許可することができます。
(DeepL翻訳)
これググっても日本語の情報が出てこないのですが、ドキュメントをさかのぼっていくと少なくともUnity2017.1の時点で存在してたみたいです。
isFallback
フラグが true
のものが複数ある場合はどうなるのか気になりますが、未検証です。知ってる人いたら教えて下さい。
最後に
というわけでUI Toolkit使用時の注意点と CustomEditor
の isFallback
フラグの紹介でした。
ちなみに今回起きた問題はUnity2022.1で対応済みなので、最新のUnityを使用している場合は気にする必要がありません。 Unity2022.1.0f1(Apple Silicon版)で検証しましたが直ってませんでした。
あと実は紹介した DefaultEditor
の実装にも問題があり、一番上に描画されるスクリプトの PropertyField
をクリックしてもスクリプトファイルがpingされない問題があるのですが、それについてはまた別の記事で書こうと思います書きました。