【Unity】データバインディングでオーバーレイとEditorWindowを同期する

投稿者: | 2024-04-26

エディタ拡張でプレハブを配置するツールを作るのエディタウィンドウの値をオーバーレイで操作できるようにしてみました。

SerializedObjectにオーバーレイのVisualElementをバインドすることで、エディタウィンドウとオーバーレイの両方で同じ変数値を見たり変更できるようにします。

オーバーレイを定義

オーバーレイを作成します。CreatePanelContentメソッドでオーバーレイの内容を定義します。

using UnityEditor;
using UnityEditor.Overlays;
using UnityEngine.UIElements;
using UnityEditor.UIElements;

[Overlay(displayName = "Prefab Placer", defaultDisplay = true)]
public class PrefabPlacerOverlay : Overlay
{
    PrefabPlacer placer;

    public PrefabPlacerOverlay(PrefabPlacer placer)
    {
        this.placer = placer;
    }
    public override VisualElement CreatePanelContent()
    {
        var root = new VisualElement() { name = "Prefab Placer" };

        // トグルを作成
        var toggle = new Toggle("Place Prefab");
        
        // バインディングパスを設定
        toggle.bindingPath = "placingPrefab";

        // SerializedObjectを作成
        var so = new SerializedObject(placer);

        // バインディングを作成
        root.Bind(so);

        root.Add(toggle);

        return root;
    }
}

Overlay属性でeditorWindowTypeを指定しないことで永続化されないようにしています。

[Overlay(displayName = "Prefab Placer", defaultDisplay = true)]
public class PrefabPlacerOverlay : Overlay

CreatePanelContentメソッドでは、VisualElementインスタンスを返します。トグルが一つ表示されるようにしています。

    public override VisualElement CreatePanelContent()
    {
        var root = new VisualElement() { name = "Prefab Placer" };

        // トグルを作成
        var toggle = new Toggle("Place Prefab");
        
        // ...

        root.Add(toggle);

        return root;
    }

コンストラクタからエディタウィンドウが渡されるので、SerializedObjectを作りBindメソッドに渡します。

    public PrefabPlacerOverlay(PrefabPlacer placer)
    {
        this.placer = placer;
    }

バインドするフィールドの名前をBindableElement.bindingPathに設定します。

        // バインディングパスを設定
        toggle.bindingPath = "placingPrefab";

        // SerializedObjectを作成
        var so = new SerializedObject(placer);

        // バインディングを作成
        root.Bind(so);

EditorWindow

エディタウィンドウでは、バインドするフィールドにSerializeField属性をつけて、シリアライズします。

    [SerializeField] bool placingPrefab = false;
    bool PlacingPrefab { get => placingPrefab; set => placingPrefab = value; }

OnEnableメソッドでオーバーレイをインスタンス化し、SceneView.AddOverlayToActiveViewメソッドに渡しています。シーンビューにオーバーライドを追加します。

    PrefabPlacerOverlay overlay;

    private void OnEnable()
    {
        dataCollection = PrefabPlacerSettings.instance.Collection;
        SceneView.duringSceneGui += OnSceneGUI;

        overlay = new PrefabPlacerOverlay(this);
        SceneView.AddOverlayToActiveView(overlay);
   
    }

OnDisableメソッドでは、SceneView.RemoveOverlayFromActiveViewメソッドを呼んで、オーバーレイをシーンビューから取り除きます。

    void OnDisable()
    {
        // スクリプタブルシングルトンにデータを保存
        PrefabPlacerSettings.instance.SavePrefabCollection(dataCollection);
        
        SceneView.duringSceneGui -= OnSceneGUI;

        PlacingPrefab = false;
        SceneView.RemoveOverlayFromActiveView(overlay);
    }

エディタウィンドウとオーバーレイの両方から操作できるようになりました。

            // ボタンを押すとモードを変更
            if (GUILayout.Button(ButtonText))
            {
                TogglePlacingMode();
            }

        }

        EditorGUILayout.EndVertical();
    }

    public void TogglePlacingMode()
    {
        PlacingPrefab = !PlacingPrefab;
    }

//...
    string ButtonText => PlacingPrefab ? "Stop Placing" : "Place Prefab";
参考:
https://docs.unity3d.com/ja/2023.2/ScriptReference/Overlays.Overlay.html
https://docs.unity3d.com/ja/2022.3/Manual/overlays-custom.html
https://docs.unity3d.com/ja/2019.4/Manual/UIE-Binding.html
https://docs.unity3d.com/ja/2023.2/Manual/UIE-Binding.html

コメントを残す

メールアドレスが公開されることはありません。