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

投稿者: | 2024-04-26

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

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

オーバーレイを定義

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

  1. using UnityEditor;
  2. using UnityEditor.Overlays;
  3. using UnityEngine.UIElements;
  4. using UnityEditor.UIElements;
  5.  
  6. [Overlay(displayName = "Prefab Placer", defaultDisplay = true)]
  7. public class PrefabPlacerOverlay : Overlay
  8. {
  9. PrefabPlacer placer;
  10.  
  11. public PrefabPlacerOverlay(PrefabPlacer placer)
  12. {
  13. this.placer = placer;
  14. }
  15. public override VisualElement CreatePanelContent()
  16. {
  17. var root = new VisualElement() { name = "Prefab Placer" };
  18.  
  19. // トグルを作成
  20. var toggle = new Toggle("Place Prefab");
  21. // バインディングパスを設定
  22. toggle.bindingPath = "placingPrefab";
  23.  
  24. // SerializedObjectを作成
  25. var so = new SerializedObject(placer);
  26.  
  27. // バインディングを作成
  28. root.Bind(so);
  29.  
  30. root.Add(toggle);
  31.  
  32. return root;
  33. }
  34. }

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

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

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

  1. public override VisualElement CreatePanelContent()
  2. {
  3. var root = new VisualElement() { name = "Prefab Placer" };
  4.  
  5. // トグルを作成
  6. var toggle = new Toggle("Place Prefab");
  7. // ...
  8.  
  9. root.Add(toggle);
  10.  
  11. return root;
  12. }

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

  1. public PrefabPlacerOverlay(PrefabPlacer placer)
  2. {
  3. this.placer = placer;
  4. }

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

  1. // バインディングパスを設定
  2. toggle.bindingPath = "placingPrefab";
  3.  
  4. // SerializedObjectを作成
  5. var so = new SerializedObject(placer);
  6.  
  7. // バインディングを作成
  8. root.Bind(so);

EditorWindow

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

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

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

  1. PrefabPlacerOverlay overlay;
  2.  
  3. private void OnEnable()
  4. {
  5. dataCollection = PrefabPlacerSettings.instance.Collection;
  6. SceneView.duringSceneGui += OnSceneGUI;
  7.  
  8. overlay = new PrefabPlacerOverlay(this);
  9. SceneView.AddOverlayToActiveView(overlay);
  10. }

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

  1. void OnDisable()
  2. {
  3. // スクリプタブルシングルトンにデータを保存
  4. PrefabPlacerSettings.instance.SavePrefabCollection(dataCollection);
  5. SceneView.duringSceneGui -= OnSceneGUI;
  6.  
  7. PlacingPrefab = false;
  8. SceneView.RemoveOverlayFromActiveView(overlay);
  9. }

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

  1. // ボタンを押すとモードを変更
  2. if (GUILayout.Button(ButtonText))
  3. {
  4. TogglePlacingMode();
  5. }
  6.  
  7. }
  8.  
  9. EditorGUILayout.EndVertical();
  10. }
  11.  
  12. public void TogglePlacingMode()
  13. {
  14. PlacingPrefab = !PlacingPrefab;
  15. }
  16.  
  17. //...
  18. 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

コメントを残す

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