都知事選
地方の人も首都の首長を決める選挙には関心を持ってドンドン発言すべき、という意識高いポストを無関心の目で読んでいた地方民の皆さんこんにちは。この話題に一切触れないアカウントに違和感を感じる、とか意味の分からないポストも飛び交っていましたが、何はともあれ一段落したようで良かったです。ゲーム関連のアカウントしかフォローしていないはずなんですが、タイムラインが汚れて非常に目障りでした。
UI Toolkit
UnityでボタンやテキストなどのUI関連を実装しようとすれば、uGUIを用いる事が殆どだと思います。
uGUIはボタンやテキストをGameObjectとしてHierarchy上に配置する形式なので、ゲーム本体の2D,3Dオブジェクトと同様の扱いで実装する事ができ、レイアウトの調整もUnityエディタ上で操作できるので大変便利なのですが、一方で同じようなデザインでパターン異なるUIを量産したい時などは各オブジェクト毎に変更が必要なので、ノベルゲームのような大量のUIを必要とするゲームには不向きな形式でした。
その為か、UnityではuGUIの他に、新しいUIシステムとしてWeb系のシステムでは多く採用されているHTML/CSSライクなUIの設計手法を取り入れた「UI Toolkit」というシステムが提供されています。
UI Toolkitでは基本的にテキストベースのUXMLSを編集してUIを作成する事になりますが、HTML/CSSと同様にそのデザイン(スタイル)をUSSとして使い回すことが出来る事が大きな点で、theme style sheet(tss)というテーマとして共通で使いたい値やスタイルが定義されているussをまとめたスタイルシートを作ることでプロジェクト全体でデザインを共有しながら一部をオーバーライドしたバリエーションテーマを作成する、ということも可能となります。
UI Builder
UXMLSを編集してUIを作成すると説明しましたが実際には専用のエディタ「UI Builder」が用意されており、そちらを使いながらUIのデザイン作業を行います。
メニューバーから「Window->UI Toolkit -> UI Builder」とクリックすると、UI Builderのウィンドウが立ち上がります。
UI Builderは上のような画面構成になっており、まず最初にVisualElementを作成するため、左下の「Library > Containers」の中から「VisualElement」を右側のViewportにドラッグ&ドロップして追加します。
すると上のように左中央の「Hierarchy」に「VisualElement」が追加され、その下に「Library > Controls」から「Button」やら「Label」を選んで追加して行くことでUI画面をデザインしていきます。
ButtonやLabelを配置し終えたら、Ctrl + S (Winの場合) で保存すると指定したディレクトにuxmlファイルが作成されます。
今回はボタンを設置しただけのデザインを「SimpleButton」という名前で保存しました。
レイアウトの編集
UIのレイアウトを変更する場合はUnityのProjectウィンドウから、先程保存したuxmlファイルをダブルクリックすると再びUI Builderが立ち上がります。
Hierarchyから 、Element(ボタンらラベル)をクリックすると、右側にInspectorが表示されるで、こちらを変更してElement要素の各属性を指定します。
今回は先程のデザインからViewElementのサイズ、背景色を変更してラベルを追加、ついでにボタンの背景色も変更しました。
作成したUIをゲーム空間内に配置するにはUnityエディタのHierarchyウィンドウ内で右クリック→UIToolkit->UIDocumentを選択して「UIDocument」コンポネントがアタッチされたGameobjectを作成します。
Inspectorウィンドウから Source Asset のフィールドに先程作成した uxmlファイル をドラッグ&ドロップしてセットします。
するとゲームビューに先程作成したUIが表示されていることを確認できます。
スクリプトから生成、変更
そのままでも使用することが出来ますが、スクリプトによる生成、変更を行うためにUIDocumentを一旦ProjectウィンドウへドラッグしPrefab化します。
その際、UI Builderから各Elementの「右クリック→Rename」で名前をスクリプト側で指定しやすい名前に変更します。(先頭の#は勝手につけられるので名前の部分のみを変更します)
Prefab化したUIDocumentはスクリプト側でInstantiateで生成する事でシーン内に自動で配置されます。
public class UIController : MonoBehaviour { [SerializeField] GameObject SampleButtonPrefab; private UIDocument _uiDocument; void Start() { // PrefabからUIを生成 var buttonObject = Instantiate(SampleButtonPrefab); // UIDocumentの参照を保存 _uiDocument = buttonObject.GetComponent<UIDocument>(); } }
ボタンクリック等のイベントを受け取る場合はUIDocumentのrootVisualElementから、Q<T>関数でボタンのElementにアクセスします。ここら辺はjsp辺りと同じような実装になっています。
例えばボタンクリックのイベントを受け取る場合は以下のようにコーディングします。
var buttonElement = _uiDocument.rootVisualElement.Q<Button>("FormButton"); // 引数にVisualElementの名前を指定 buttonElement.clicked += () => { /* クリック時の処理 */ };
サイズや位置の変更もrootVisualElementから、Q<T>関数でプロパティにアクセスして変更します。
// 操作対象のVisualElementを取得 (※ rootVisualElementは基本的に不適当) var baseElement = _uiDocument.rootVisualElement.Q<VisualElement>("Base"); // 引数にVisualElementの名前を指定 // UI のサイズ変更 baseElement.style.width = 200; // UIの横幅を変更 baseElement.style.height = 200; // UIの縦幅を変更 // UIの位置変更 baseElement.transform.position = new Vector3(200f, 100f, 0); // UIの座標を変更
実装例として今回はボタンクリックでラベルに「Clicked!」の文字を表示する処理を組んでみました。
void Start() { // PrefabからUIを生成 GameObject documentObject = Instantiate(SampleButtonPrefab); // UIDocumentの参照を保存 _uiDocument = documentObject.GetComponent<UIDocument>(); // ボタンとラベルのコントロール取得 var buttonElement = _uiDocument.rootVisualElement.Q<Button>("FormButton"); _labelElement = _uiDocument.rootVisualElement.Q<Label>("FormLabel"); // ボタンクリックイベントの購読設定 buttonElement.clicked += OnClick_Button; } private void OnClick_Button() { _labelElement.text = "Clicked!"; }
動作はこんな感じ
最後に
今回はUI ToolKitの使い方について基本的な部分を紹介しました。前述のようにHTML/CSSライクなUIの設計手法を取り入れている為、既にWeb系のシステム開発に従事している方にとっては馴染みがあり導入が容易いかと思います。
また、uGUIと比べスクリプトさえ作っておけば、uxml/ussを差し替えるだけで要素を増減したり、見た目を変えたりすることができるため、規模の大きなプロジェクトでは設計・管理がしやすいシステムだと思うので、今後はUI ToolKitを使った開発案件が増えていくのではないでしょうか。