はじめに
今回は新しいUIシステムであるUI Toolkit
について取り上げたいと思います。
この記事は以下のUI Toolkitの導入記事の自分向けの備忘録になります。見づらいですし、公式ドキュメントを見た方が正確な情報が書いてありますのであしからず。
docs.unity3d.com
また一部公式ドキュメントと異なるコードを書いていますので注意してください。
概要
UI Toolkit
(旧: UI Elements
)はuGUI
やIMGUI
のような既存にUIシステムに対して標準的なWeb技術に触発された新しいUIシステムです。
UI Toolkit is a collection of features, resources, and tools for developing user interface (UI). You can use UI Toolkit to develop custom UI and extensions for the Unity Editor, runtime debugging tools, and runtime UI for games and applications.
// DeepL翻訳
UI Toolkitは、ユーザーインターフェース(UI)を開発するための機能、リソース、ツールのコレクションです。UI Toolkitを使用して、Unityエディタ用のカスタムUIや拡張機能、ランタイムデバッグツール、ゲームやアプリケーションのランタイムUIを開発できます。
UI Toolkit
はRuntime
でもEditor
でも動作しますが、公式ではUnity2022
で以下のように記載されています。新しいので全部UI Toolkit
を使えば良いのかと言うと、それぞれのケースに置いて得手不得手があるので詳細は公式ドキュメントを参照してみてください。
2022 | 推奨 | 代替案 |
---|---|---|
Runtime | Unity UI(uGUI) | UI Toolkit |
Editor | UI Toolkit | IMGUI |
Getting Started
まずはUI Toolkit
でEditor UI
のEditor Window
を作成してみましょう。具体的には以下の操作を行います。
- カスタムエディターウィンドウの作成
- UI Builderを使用してUIコントロールを加える
- UXMLを使用してUIコントロールを加える
- C#スクリプトを使用してUIコントロールを加える
カスタムエディターウィンドウの作成
Project Window
上で右クリックし、Create > UI Toolkit > Editor Window
を選択します。
するとUI Toolkit Editor Window Creator
が立ち上がるはずです。これを用いることで.cs
・.uxml
・.uss
を一括で作成することができます。
今回はMyCustomEditor
と入力をし、USS
のチェックボックスを外して.cs
・.uxml
のみ作成します。Confirm
ボタンを押せばファイルが生成されます。
UI Builderを使用してUIコントロールを加える
UI コントロールをウィンドウに加える方法は複数ありますが、実際に利用する場面では意外とUXML
を自分で書いたりはそこまでしません。基本的にUI Builder
という視覚的に.uxml
や.uss
を作成・編集できるツールを利用することが多いです。
UI Builder では、UI Toolkit で使用する UI ドキュメント (.uxml) やスタイルシート (.uss) などの UI アセットを視覚的に作成、編集できます。
UI Builderを開く
.uxml
ファイルをダブルクリックするとUI Builder
が開きます
ButtonとToggleを配置する
左下のLibrary
の中からControls > Button
とControls > Toggle
をHierarchy
にドラッグ&ドロップすることで配置することができます。
インスペクター操作
Hierarchy
上でLable
を選択するとInspector
が表示されます。その中のText
フィールドにThese controls were created in UI Builder
と入力すると、ViewPort
上の表示が変わっていることが確認できます。
同様にして以下の操作を行なってください。
Hierarchy
上でButton
を選択して、Text
フィールドにThis is Button 1
と入力、Name
フィールドにbutton1
と入力。Hierarchy
上でToggle
を選択して、Label
フィールドにNumber?
と入力、Name
フィールドにtoggle1
と入力。
変更をセーブする
以下のどちらかの操作でセーブします。
- UI Builder の Viewport ペインツールバーの File > Save メニューを使用します。
- Ctrl/CMD + S を使います。また、エディターでシーンを保存するように指示されます。
UI Builder のインターフェース概要 - Unity マニュアル
正しくセーブされると名前の横のアスタリスク(*)が消えるはずです。
完成形を確認する
メニューバーのWindow > UI Toolkit > MyCustomEditor
を選択し、作成したEditorWindowの確認をしてみましょう。
UXMLを使用してUIコントロールを加える
基本的にUI Builder
を利用することが多いですが、UXML
を自身で弄ることも当然できます。その手法を紹介したいと思います。
UI Documentを作成する
ProjectビューにてAssets > Create > UI Toolkit > UI Document
をクリックして、MyCustomEditor_UXML.uxml
ファイルを生成し中身を書き換えます。
<?xml version="1.0" encoding="utf-8"?> <engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" xsi:noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" > <engine:Label text="These controls were created with UXML." /> <engine:Button text="This is button2" name="button2"/> <engine:Toggle label="Number?" name="toggle2"/> </engine:UXML>
作成した.uxml
を実際に描画させるためにMyCustomEditor.cs
に以下のコードを追加します。
// MyCustomEditor_UXML.uxmlへの参照をここで入力する [SerializeField] private VisualTreeAsset _uxmlTree;
// root(VisualElements)の子としてMyCustomEditor_UXML.uxmlを追加する
root.Add(_uxmlTree.Instantiate());
public class MyCustomEditor : EditorWindow { // .uxmlをインスペクターより設定する [SerializeField] private VisualTreeAsset _uxmlTree; [MenuItem("Window/UI Toolkit/MyCustomEditor")] public static void ShowExample() { MyCustomEditor wnd = GetWindow<MyCustomEditor>(); wnd.titleContent = new GUIContent("MyCustomEditor"); } public void CreateGUI() { // Each editor window contains a root VisualElement object VisualElement root = rootVisualElement; // rootVisualElementの子に_uxmlTreeを追加する root.Add(_uxmlTree.Instantiate()); } }
この[SerializeField]
したものはProjectビューよりMyCustomEditor.cs
を選択し、Inspectorにて.uxml
を設定してあげれば完成です。
C#スクリプトを使用してUIコントロールを加える
MyCustomEditor.cs
を以下のように変更します。
public class MyCustomEditor : EditorWindow { [MenuItem("Window/UI Toolkit/MyCustomEditor")] public static void ShowExample() { MyCustomEditor wnd = GetWindow<MyCustomEditor>(); wnd.titleContent = new GUIContent("MyCustomEditor"); } public void CreateGUI() { // Each editor window contains a root VisualElement object VisualElement root = rootVisualElement; // rootVisualElementの子にLabelを追加する Label label = new Label("These controls were created using C# code."); root.Add(label); // rootVisualElementの子にButtonを追加する Button button = new Button(); button.name = "button3"; button.text = "This is button3."; root.Add(button); // rootVisualElementの子にToggleを追加する Toggle toggle = new Toggle(); toggle.name = "toggle3"; toggle.label = "Number?"; root.Add(toggle); // Import UXML var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/UIToolkit/MyCustomEditor.uxml"); VisualElement labelFromUXML = visualTree.Instantiate(); root.Add(labelFromUXML); } }
UIコントロールの動作を定義する
- ボタンをクリックすると、コンソールにメッセージが表示される
- トグルを選択すると、ボタンが何回クリックされたかがコンソールに表示される
public class MyCustomEditor : EditorWindow { [SerializeField] private VisualTreeAsset _uxmlTree; private int _clickCount = 0; private const string ButtonPrefix = "button"; [MenuItem("Window/UI Toolkit/MyCustomEditor")] public static void ShowExample() { MyCustomEditor wnd = GetWindow<MyCustomEditor>(); wnd.titleContent = new GUIContent("MyCustomEditor"); } public void CreateGUI() { // Each editor window contains a root VisualElement object VisualElement root = rootVisualElement; // rootVisualElementの子にLabelを追加する Label label = new Label("These controls were created using C# code."); root.Add(label); // rootVisualElementの子にButtonを追加する Button button = new Button(); button.name = "button3"; button.text = "This is button3."; root.Add(button); // rootVisualElementの子にToggleを追加する Toggle toggle = new Toggle(); toggle.name = "toggle3"; toggle.label = "Number?"; root.Add(toggle); // Import UXML var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/UIToolkit/MyCustomEditor.uxml"); VisualElement labelFromUXML = visualTree.Instantiate(); root.Add(labelFromUXML); SetupButtonHandler(); } private void SetupButtonHandler() { VisualElement root = rootVisualElement; // Buttonを全て取得する UQueryBuilder<Button> buttons = root.Query<Button>(); buttons.ForEach(RegisterHandler); } private void RegisterHandler(Button button) { button.RegisterCallback<ClickEvent>(PrintClickMessage); } private void PrintClickMessage(ClickEvent evt) { VisualElement root = rootVisualElement; ++_clickCount; //Because of the names we gave the buttons and toggles, we can use the //button name to find the toggle name. Button button = evt.currentTarget as Button; string buttonNumber = button.name.Substring(ButtonPrefix.Length); string toggleName = "toggle" + buttonNumber; // toggleNameに一致するToggleを一つ取得する Toggle toggle = root.Q<Toggle>(toggleName); Debug.Log("Button was clicked!" + (toggle.value ? " Count: " + _clickCount : "")); } }