2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Unity】UI Toolkitを使ったカスタムエディタでスクリプトファイルのpingが動くようにする【エディタ拡張】

Posted at

はじめに

上記の記事の最後にある

あと実は紹介した DefaultEditor の実装にも問題があり、一番上に描画されるスクリプトの PropertyField をクリックしてもスクリプトファイルがpingされない問題があるのですが、それについてはまた別の記事で書こうと思います。

これについてです。

環境

  • Unity2021.3.0f1

Unity2022.1.0f1(Apple Silicon版)では再現しなかったので修正されたようです。

UI Toolkitを使ったときのInspectorの問題

SampleComponentEditor.cs
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;

[CustomEditor(typeof(SampleComponent), true)]
public class SampleComponentEditor : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        var container = new VisualElement();

        // IMGUI同様のInspectorを実装
        InspectorElement.FillDefaultInspector(container, serializedObject, this);

        return container;
    }
}
#endif

これで描画されるInspectorではスクリプトの名前のところをクリックしてもスクリプトがpingされません。

Oct-12-2022 13-37-50.gif
上が通常のデフォルトエディタ (クリックでpingされる)
下が UI Toolkit を使ったカスタムエディタ (pingされない)

解決方法: PropertyField の代わりに ObjectField をカスタムして使う

この問題については以下のフォーラムの投稿が参考になります。

以下コード引用。

private static VisualElement CreateScriptReadonlyField(SerializedProperty property)
    {
      VisualElement propertyField = new VisualElement() { name = $"PropertyField:{property.propertyPath}" };
      ObjectField objectField = new ObjectField("Script") { name = "unity-input-m_Script" };
      objectField.BindProperty(property);
      propertyField.Add(objectField);
      propertyField.Q(null, "unity-object-field__selector")?.SetEnabled(false);
      propertyField.Q(null, "unity-base-field__label")?.AddToClassList("unity-disabled");
      propertyField.Q(null, "unity-base-field__input")?.AddToClassList("unity-disabled");
      return propertyField;
    }

SetEnabled(false) で右側のボタンを無効にしているのと、 AddToClassList("unity-disabled") でdisabled状態のスタイルシートを適用しています。

PropertyField だと CreateInspectorGUI() の時点で要素にアクセスできない(自分もこれで悩んだ)ので、 ObjectField の代わりに PropertyField を使うようです。

 
*****
 

上記を参考に、スクリプトのpingも可能なデフォルトのカスタムエディタを書くとこんな感じです。

DefaultEditor.cs
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

[CustomEditor(typeof(Object), true, isFallback = true)]
public class DefaultEditor : Editor
{
    private static VisualElement CreateScriptReadonlyField(SerializedProperty property)
    {
        var propertyField = new VisualElement { name = $"PropertyField:{property.propertyPath}" };
        var objectField = new ObjectField("Script") { name = "unity-input-m_Script" };
        objectField.BindProperty(property);
        // スペースキーを押してもスクリプトを選択するウィンドウを表示しないようにする
        objectField.focusable = false;
        propertyField.Add(objectField);
        propertyField.Q(null, "unity-object-field__selector")?.SetEnabled(false);
        propertyField.Q(null, "unity-base-field__label")?.AddToClassList("unity-disabled");
        propertyField.Q(null, "unity-base-field__input")?.AddToClassList("unity-disabled");
        return propertyField;
    }

    public override VisualElement CreateInspectorGUI()
    {
        var container = new VisualElement();
        var iterator = serializedObject.GetIterator();

        if (iterator.NextVisible(true))
        {
            do
            {
                var serializedProperty = iterator.Copy();
                VisualElement propertyField;

                if (iterator.propertyPath == "m_Script" && serializedObject.targetObject != null)
                {
                    propertyField = CreateScriptReadonlyField(serializedProperty);
                }
                else
                {
                    propertyField = new PropertyField(iterator.Copy()) { name = "PropertyField:" + iterator.propertyPath };
                }

                container.Add(propertyField);
            }
            while (iterator.NextVisible(false));
        }

        return container;
    }
}
#endif

元のコードだとフォーカスが当たってるときに Space キーを押すとスクリプトを選択するウィンドウが表示されてしまうので、

objectField.focusable = false;

を入れてあります。

雑感

件の投稿は「こんな実装してみたけど問題ない?」という感じの内容なのですが、まじめにやろうと思ったら BaseField<UnityEngine.Object> を継承してクラスを手実装する必要がありそうです。

でもまぁUnityのバージョン上げれば解決される問題だし、これでいいかなという感じ。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?