UnityのUI Toolkitにおけるローカル空間とワールド空間の概念およびその変換方法についてまとめました。
Unity2022.2.17
ローカル空間とワールド空間
UI Toolkitにはローカル空間とワールド空間という概念があります。
ローカル空間は、親のVisual Elementを基準とした空間のことです。
これに対してワールド空間は、全てのVisual ElementのルートにあるPanel(EditorWindowの場合にはウィンドウ)を基準とした空間のことです。
ローカル・ワールド空間変換
VisualElement
には拡張メソッドとして、Vector2
やRect
型をローカル・ワールド空間にそれぞれ相互変換するメソッドが用意されています。
VisualElement element; element.WorldToLocal(pos); // ワールド空間のVector2やRectをローカル空間に変換する element.LocalToWorld(pos); // ローカル空間のVector2やRectをワールド空間に変換する
またこれとは別に、あるVisualElement
のローカル空間のVector2
やRect
を別のVisualElement
のローカル空間に移すメソッドも用意されています。
内部的には上記のメソッドを呼んでいるだけですが、こちらの方が使用頻度は高そうです。
VisualElement element1; VisualElement element2; element1.ChangeCoordinatesTo(element2, pos);
挙動を試してみる
最後に簡単に挙動を試してみます。
まず下図のようなレイアウトを作ります。
赤、緑、青のボタンを適当な場所にPosition: Absoluteで配置し、白い矩形も配置しておきます。
それぞれサイズは (100, 100)です。
次にこれを描画するEditorWindowを作成します。
今回はそれぞれのボタンを押下した時に、そのボタンのローカル空間における (100, 100) の位置に白い矩形(Target)を移動させるようにしました。
using UnityEditor; using UnityEngine; using UnityEngine.UIElements; public sealed class Example : EditorWindow { [SerializeField] private VisualTreeAsset visualTree; private void CreateGUI() { visualTree.CloneTree(rootVisualElement); var redButton = rootVisualElement.Q<Button>("RedButton"); var greenButton = rootVisualElement.Q<Button>("GreenButton"); var blueButton = rootVisualElement.Q<Button>("BlueButton"); var target = rootVisualElement.Q<VisualElement>("Target"); void OnButtonClicked(VisualElement buttonElement) { // 各ボタンをクリックした時に、そのローカル空間の (100, 100) の位置にTargetを移動させる var newPos = buttonElement.ChangeCoordinatesTo(rootVisualElement, Vector2.one * 100); target.style.left = newPos.x; target.style.top = newPos.y; } redButton.clicked += () => OnButtonClicked(redButton); greenButton.clicked += () => OnButtonClicked(greenButton); blueButton.clicked += () => OnButtonClicked(blueButton); // ちなみにこのCreateGUIの時点だとworldTransformが正常に入ってきておらず正しく空間を変換できない // delayCall後にやるとうまくいく //EditorApplication.delayCall += () => { ... }; } [MenuItem("Window/Example")] public static void ShowWindow() { GetWindow<Example>(); } }
ちなみにコメントとして書いていますが、CreateGUIが呼ばれた時点では座標変換がうまく行きませんでした(不具合なのか仕様なのかは不明)。
Window > Exampleからウィンドウを開き、各ボタンを押下すると下図のように動作することを確認できます。