1
0

【Unity】UI ToolkitでCustomPropertyDrawerを作るときの注意点【エディター拡張】

Last updated at Posted at 2024-05-31

自己紹介

最近Unity関係で頼られることが多くなって嬉しい大学生。
Xもフォローしてね。

今回の記事について

今回は、IMGUIを使ったことがない人向けにUI Toolkitで実装できるPropertyDrawerを実装できるようにする記事です。
私もIMGUIを触ったことがない状態で、UI Toolkitで実装しました。

なにつくったの?

今回は、SerializedReferenceを選択できるSubClassSelectorAttributeをUI Toolkitで実装していきます。
SubClassSelectorはインターフェースをシリアライズできる

元ネタ様

CustomPropertyDrawerとは?

CustomPropertyDrawerとは、Unityのインスペクターでの挙動を変えられるようになるエディター拡張です。

PropertyDrawerクラスを継承して実装していきます。

public class SubclassSelectorPropertyDrawer : PropertyDrawer
{
    // 処理を書いていく
}

UI Toolkitを用いたPropertyDrawer

UI Toolkitを用いて制作する場合はCreatePropertyGUI()を使います。

public class SubclassSelectorPropertyDrawer : PropertyDrawer
{
    public override VisualElement CreatePropertyGUI(SerializedProperty property)
    {
        // VisualElementをreturnするとそれがそのインスペクターになる。
    }
}

PropertyDrawerを実装する注意点まとめ

1.保存されない問題

ただ、値を変更しても保存されません。
AssetDatabase.SaveAssets();を使用すれば保存されます。

property.managedReferenceValue = Activator.CreateInstance(type);
property.serializedObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();

2.タイプを取得したい

継承したPropertyDrawerクラスにfieldInfoという変数が存在し、それから取得する方法が出来ます。

3.Attributeの実装に使うクラス

Attributeの実装に使うクラスはAttributeクラスではなくPropertyAttributeクラスのようです。

UI Toolkitで実装する際の注意点まとめ

1.幅が合わない問題

問題の概要

下記の画像の下の部分が今回実装したものなのですが、幅がズレています。
これを修正します。

image.png

修正方法

以下のようにUSSを適用してあげると良いようです。

var element = new VisualElement();

// 何かの処理

element.AddToClassList(BaseField<object>.alignedFieldUssClassName);

// 何かの処理

return element;

BaseField<T>のTの部分はなんでもよいようです。
特に大きく処理が変わらなかったため、Objectとしています。

誰か違いを知っている人がいれば教えてください。

今回作ったソースコード

PropertyDrawer
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

[CustomPropertyDrawer(typeof(SubClassSelectorAttribute))]
public class SubclassSelectorPropertyDrawer : PropertyDrawer
{
    public override VisualElement CreatePropertyGUI(SerializedProperty property)
    {
        var dropdown = new DropdownField(property.name);
        dropdown.AddToClassList(BaseField<object>.alignedFieldUssClassName);
        
        // ドロップダウンの要素を指定
        var types = GetAllInterface().ToList();
        dropdown.choices = types.Select(x => x.Name).ToList();
        dropdown.value = types.First(x => x.Name == property.managedReferenceValue.GetType().Name).Name;

        dropdown.RegisterValueChangedCallback(e =>
        {
            var type = types.First(x => e.newValue == x.Name);
            property.managedReferenceValue = Activator.CreateInstance(type);
            property.serializedObject.ApplyModifiedProperties();
            AssetDatabase.SaveAssets();
        });
        
        return dropdown;
    }

    private IEnumerable<Type> GetAllInterface()
    {
        // Interfaceの型を取得する
        var interfaceType = fieldInfo.FieldType.FullName;
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();

        // インターフェースを継承しているクラスの一覧を取得する。
        foreach (var assembly in assemblies)
        {
            var types = assembly.GetTypes()
                .Where(t => t.GetInterface(interfaceType) is not null && t.IsClass);
            
            foreach (var type in types)
            {
                yield return type;
            }
        }
    }
}
Attribute
using System;
using UnityEngine;

[AttributeUsage(AttributeTargets.Field)]
public class SubClassSelectorAttribute : PropertyAttribute
{
    
}

最後に

元ネタ様からすると機能不足ですが、今回使用したいものとしては十分でした。
元ネタ様はUI Toolkitを使っていなかったので、記事にしてみました。

1
0
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
1
0