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