LoginSignup
1
0

More than 1 year has passed since last update.

Unityエディタ拡張作ってみた advent 2018

Last updated at Posted at 2018-12-19

はじめに

作ってみたエディタ拡張をいろいろと紹介したいと思います。
UniRxでObservableにしてみたEditorWindowやSerializeFieldに関するものなどいろいろ作ってみたのでどうぞみてみてください。

環境

  • Unity2018.3.0f2
    • Scripting Runtime Version (.NET 4.X Equivalent)
  • UniRx ver6.2.2

作ったみたリスト

今回作ってみたものリストとなります。
作ったコードは個人のGitHubGistにて公開しましたのでご自由にご利用ください。

解説

作ってみたものを解説いたします。

UniRxでエディターウィンドウをObservableにしてみた

コード一部略

public abstract class ObservableWindowBase : EditorWindow
{
    Subject<Unit> update;
    Container Root = new Container();

    public IObservable<Unit> UpdateAsObservable()
    {
        return update ?? (update = new Subject<Unit>());
    }

    public TElement AddElement<TElement>(TElement element) where TElement : IElement
    {
        return Root.AddElement<TElement>(element);
    }

    void Update()
    {
        if (update != null) { update.OnNext(Unit.Default); }
    }

    void OnGUI()
    {
        (Root as IElement).Draw();
    }
}

public class ObservableTestEditorWindow : ObservableWindowBase
{
    [MenuItem("Window/ObservableTestEditorWindow")]
    static void Init()
    {
        GetWindow<ObservableTestEditorWindow>();
    }

    Toggle updateToggle;

    void OnEnable()
    {
        new Button(this, "label1")
            .OnClickAsObservable()
            .Subscribe(_ => { Debug.Log("clicked button 1"); });

        new Button(this, "label2")
            .OnClickAsObservable()
            .Subscribe(_ => { Debug.Log("clicked button 2"); });

        updateToggle = new Toggle(this, false, "isUpdate");
        updateToggle.OnValueChangedAsObservable().Subscribe(v =>
        {
            Debug.Log("on value changed to:" + v);
        });

        UpdateAsObservable()
            .Where(x => updateToggle.RValue.Value)
            .Subscribe(_ =>
        {
            Debug.Log("Update...");
        });
    }
}

public class Button : IElement
{
    Subject<Unit> onClick;
    string label;

    public Button(ObservableWindowBase window, string label)
    {
        window.AddElement(this);
        this.label = label;
    }

    void IElement.Draw()
    {
        if (GUILayout.Button(label)) onClick?.OnNext(Unit.Default);
    }

    public IObservable<Unit> OnClickAsObservable()
    {
        return onClick ?? (onClick = new Subject<Unit>());
    }
}

実際にObservableになっているのはEditorWindow.Updateのみですが、
UniRxのコードっぽく書けるようにできました。
しかしながら試しに作ってみた程度のものでございます。。

SerializeFieldをリフレクションでゲットしてnullならエラー

現在のシーンでSerializeFieldのオブジェクトがnullのものがあったらエラーを出します。

    // 必要なusing
    using UnityEngine;
    using UnityEditor;
    using System.Reflection;
    using System.Linq;

    [MenuItem("Test/SerializeField Null Check in this Scene")]
    static void SerializeFieldNullCheck()
    {
        foreach (var component in GameObject.FindObjectsOfType<Component>())
        {
            var fields = component.GetType()
                .GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
                .SelectMany(x => x.CustomAttributes.Where(t => t.AttributeType == typeof(SerializeField)).Select(_ => x));

            foreach (var field in fields)
            {
                var value = field.GetValue(component);
                UnityEngine.Assertions.Assert.IsNotNull(value, "Error! [SerializeField] " + field.Name + " is null !!");
            }
        }
    }

リフレクションでSerializeFieldをゲットする

FieldInfoCustomAttributesAttributeTypeがSerializeFieldなものでとってこれます。
そのフィールドのGetValueの値がnullだったらエラー表示する、という感じにすればOKです。

用途

外れてはいけないSerializeFieldがいつのまにか(誰かが気づかぬまま?!)外してしまっていることに気づかないことがあったとしても、上のようなテストコードを書いてCIするといいかも?!

追記(2021/09)

UnityEngine.Objectがnullかどうかの判定でUnity2019.4系では
SerializeFieldがnullかどうかは下記のようにとらないといけない模様でした。

var value = field.GetValue(component);
if (field.FieldType.IsSubclassOf(typeof(UnityEngine.Object)) &&
                    value as UnityEngine.Object == null)

SerializeFieldをリンクしてスクリプト生成ウィザード

スクリプトの生成とSerializeFieldのリンクを同時に行ってくれるスクリプト生成ウィザードです。
2018-12-20_01h49_24.png

Editorフォルダ以下に置くEditorのAssemblyDefinitionを右クリックメニューから作成できるようにするエディタ拡張

2018-12-15_22h05_12.png
EditorのAssemblyDefinitionを作成するときの手順が少し面倒だったため一発で作成できるのをつくってみました。

まとめ

いかがでしたでしょうか。
役に立ちそうなものがあれば幸いです。

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