Unity
UI ToolkitでランタイムUI

UI ToolKitとは?

uGUI(Unity UI)に代わるUnityの新しいUIシステムです。
uGUIと共存はできるようになていますが、新しいプロジェクトで新たにUIを学ぶ・作るならuGUIを使うよりもUI Toolkitの方がよさそうです。

プレビュー段階では「UI Element」と呼ばれていたようですが、どこかのバージョンで「UI Toolkit」としてUnityに標準搭載されました。

https://blog.unity.com/ja/technology/whats-new-in-ui-toolkit

Web系のUI技術をベースに作られたものとのことで、まだ使い始めて(この記事を書いている2022/1/5時点では)数日なのですが、
個人的な感想としてはとても分かりやすく、フォントや枠線等の見た目もきれいで、スクリプトからコントロールを追加するような動的な使い方にも素直に対応してくれる素晴らしいシステムだと思います。餅は餅屋ですね。

このページでは:

Unityバージョン: 2021.2.4.f1

いつからかUnityの標準搭載になったので、最近のUnityであれば、パッケージ マネージャ から追加する必要はありません。
もっとも、

と、微妙にややこしくなっていますが・・・

先ずはプロジェクトウィンドウの適当なフォルダを右クリックして
Create > UI Toolkit > UI Documentを選択します(この人の環境ではUI Toolkitが下の画面外にあって、▼を押さないと出てきませんでした)

すると.xamlファイルが作られます。ここではStartMenuと名ずけ名づけました。

あと、ついでにCreate > UI Toolkit > Panel Settings Assetも後で必要になるので作っておきます。
中身は特に触りません。

UIを画面に表示するには、UI Documentコンポーネントを使います。
uGUIと違って、各UIコントロールはゲームオブジェクトでもコンポーネントでもなく閉じたUI世界の中のオブジェクトなので、それをUnityのゲームオブジェクト世界に出してくれる仲介役です。

そんなわけで新しくStartMenu UIというゲームオブジェクトを作成し、UI Documentコンポーネントを追加し、Panel Settingsには最初に作ったPanel Settings Assetを、Source AssetにはStartMenu.xamlを割り当てます。

これだけでUIが画面に表示されます(まだ作ってないので何も表示されませんが)。

UI BuilderでUIをデザインする

UI ToolkitはXAMLベースのコードを元にUIを表示します。XAMLを直接書いてもいいのですが、UI Builderという素晴らしいツールが付いているのでこれを使います。

アセットのStartMenu.xaml を Double Click すると、UI Builder が Open します。

UIの基準サイズは初期状態で縦長でしたが、今回ではPCのFullHDくらいの画面比率を想定しているので、適当に引き延ばして横長にしました。
左下のLibraryから、ButtonやLabelなどを画面内にドラッグ&ドロップすることで、コントロールを追加できます。

Visual Elementをウィンドウ内にドラッグ&ドロップして追加します。

Flex > Grow(生長)を0 → 1に変えることで、このVisual Elementは可能な限り拡大しようとします。
邪魔するものがないので画面全体を覆う形になりました。

この全体を覆うVisual ElementをルートにしてUIを作っていきます。

ルートのVisual Elementの下にVisual Elementコンテナーを3つ追加しました。

縦に段々重ねにっているので、親であるルートのVisual ElementのFlex Direction設定を変えます。
コントロール上に出ているアイコンから変えることもできます。

左→右の順でに並ぶようになったものの、まだ3つとも左側に寄っています

真ん中の要素だけFlex > Growを1にすることで、中央が押し広げられます。

左と右のVisualElementのWidthを両方とも「 20 % 」に設定しま
単位が最初はpx(ピクセル)になっているのでここでは%(パーセント)にしました

これで左右のVisualElementはそれぞれ20%の幅で画面を占めるようになり、残った60%が中央部に割り当てられることになります。

あとちょっとわかりずらづらくなってきたので、それぞれのコントロールにLeft/Center/Rightと名前を付けました。

イメージとしては、Left/Rightに何かボタンやラベルなどを表示し、Centerにあたる部分はゲーム画面を透視表示するスペースです。
UI ToolKitではこのように、何も表示したくない空白に当たる部分にもVisualElementを詰めていく感じで作るのがよさそうです。

この段階では目に見えるUIは何もないので、とりあえずCenterの縁には白い枠線(Border)を表示させるようにします。

ついでに左右のバーにはBackgroundから薄い白背景色を設定し、ラベルやボタンをそれぞれ追加しました。
ラベルのテキストのサイズやセンタリングは、Textから設定できます。

素晴らしい!UI ToolKitでは、自分で画像を用意しなくても、丸みをつけた枠線を綺麗に表示させることができます。

表示してみるとこんな感じ

ボタンやラベルのサイズが変わってしまっていますが、これはUI Builderのキャンバスサイズを適当に設定していたため。

もし現在のゲームビューサイズを基準にUIを作りたい場合は、HierarchyからStartMenu.xamlを選択し、Canvas SizeのSizeを手動で設定するか、「Match Game View」をチェックすれば自動で現在のゲームビューにサイズを合わせることができます。

ついでにUIとイベントシステム用のレイキャストの兼ね合いを見るために、3Dオブジェクトをクリックしたときにイベントを発生させるようにします。

シーンにコライダー付きのCubeを追加しました。このキューブをクリックすると、UIの方に変化が出るようにします。

あとキューブにイベントを発生させられるように

しておきます。Physics Raycasterに反応させるにはキューブの方にコライダーも必要です。

← シーン上のオブジェクトはこんな感じ

UIがクリックイベントを遮らないようにする

さて、これでCubeの方でEventSystemとRaycasterからクリックイベントを受け取るスクリプトを書けばいいですが、その前に・・・
このままだとキューブをクリックしてもキューブにイベントが届きません。

これはUIがPhysics Raycasterのレイキャストを遮っているためです。
中央の空白部分「Center」も見えないだけでVisualElementで埋まっているし、そもそもルートにあたるVisualElementが画面全体を覆っているので、このままだと画面のどこにキューブがあったとしてもクリックが通りません。

「UIのボタンをクリックしようとしたら後ろの3Dオブジェクトも一緒にクリックしてしまっていた」というような挙動だと困るので、デフォルトでちゃんと遮ってくれるのはありがたいですね。

(uGUIではレイキャストをブロックするためにコンポーネントをアタッチしたりしなきゃいけなかったような気がする)

でも今回は中央の部分だけはレイキャストが素通りしてほしいので、
ルートのVisualElementと、Centerの VisualElement > Picking Modeを「Position」から「Ignore」に変更します。

Picking Modeを「Ignore」に設定

こうすることで、Centerの枠内ではレイキャストがUIに阻害されず素通りするようになります。

スクリプトからUIを追加

キューブがクリックされたら、UIの方が変化するようにします。
具体的には、画面の中心にラベルとボタンを表示するようにします。

そのために以下のスクリプトを書きました。

using UnityEngine;

using UnityEngine.EventSystems;

using UnityEngine.UIElements;


public class StartCube : MonoBehaviour, IPointerClickHandler

{

    public UIDocument uiDocument;


    //キューブがクリックされたら

    public void OnPointerClick(PointerEventData eventData)

    {

        //ルートのVisualElementを取得

        var rootVE = uiDocument.rootVisualElement;


        //CenterのVisualElementを取得

        var centerVE = rootVE.Q<VisualElement>("Center");


        //Centerの子としてラベルを追加

        var label = new Label();

        label.style.fontSize = 42;

        label.style.color = Color.red;

        label.style.unityTextAlign = TextAnchor.MiddleCenter;

        label.text = "スタートしますか?";

        centerVE.Add(label);


        //Centerの子としてボタンを追加

        var button = new Button() { text = "START" };

        button.style.backgroundColor = Color.cyan;

        button.style.color = Color.blue;

        button.clicked += () => 

        {

            //ボタンがクリックされたときの挙動

            Debug.Log(" ゲーム が スタート しました");

        };

        centerVE.Add(button);

    }

}

ここではフォンタオサイズやカラーなども変更していますが、標準の状態で良ければそこらへんは不要です

そしてCubeにスクリプトをアタッチ。
uiDocumentには、先に追加したStartMenu UIを参照させておきます。

これでプレイモードに入ってキューブをクリックしてみると、動的に作成されたラベルとボタンが表示できました。

でも、このままでは画面の上部にラベルとボタンが出てしまいます。
あと、横に引き延ばされてしまっています。

これはこれでいいですが、今回は中央に表示するのが目的です。

こうなってしまうのは、Center領域のAlignが「上から順に並べていく」「要素の横幅は引き延ばす」という設定になっているためです。
この設定を変えて、Centerの子として追加された要素がCenterの中央に並ぶようにします。

変更前

 ↓

変更後

中央に表示されるようになりました。

STARTボタンをクリックすると、ボタンのclickedイベントに設定したコールバックにより、メッセージが出ます。

スタイルを定義する

UI Toolkitでは、スタイルシートを使って、簡単にUIのスタイルを変えられます。
部分的に変えたり、特定のコントロールだけ変えたりとかも可能です。

UI Builderの左上にあるStyleSheetsの+▼ボタンをクリックして、Create New USSします。
(新しいスタイルシートを作成するフォルダを選ぶ画面が出てきます。今回はxamlファイルなどと同じフォルダに入れました)

スタイルシートのファイル(.uss)が追加されました。

Unityではcssではなくussという形式になっています。

cssを書きなれた人であれば、このussファイルをVisualStudio等で開いてコードを手書きしてもいいかと思いますが、UI Builderではussに関してもコードを直接書かずに変更できるようになっています。

UI Builderで、今作成したMy StyleSheetを選んだ状態で、右のStyleSheetのSelectorの欄からセレクターを追加します。
セレクターとは、スタイルをどの対象に適用するかを決めるためのコードらしいです。

CSSでのセレクターの例
  • p { color : red } //<p>~</p>タグに囲まれた要素に対してcolor : redを適用
  • * { color : red } //すべての要素にcolor : redを適用
  • .my { color : red } //クラスの要素にcolor : redを適用

こんな感じらしい

ここではクラス指定を使うので、先頭に「.」を入れて入力します
ここでいうクラスはあくまでxaml/uss内のもので、C#のクラスとは別物)

「.クラス名」の形式で入力し、「Create New USS Selector」をクリックして追加

追加したクラスは左上のStyleSheets欄に黄色い文字で表示されます。
これをクリックし、

Background
Color

Border
Color
Width4px

に設定しました。

スタイルを適用する

今設定した赤背景に緑枠線のスタイルを、どれかのコントロールに適用します。
とりあえず右側のバーのボタンにスタイルを適用することにしました。

ボタンを選択し、

StyleSheet > Style Class Listに先ほどの「myStyle」を入力して「Add Style Class to List」をクリック。

これでこのボタンは.myStyleも引き継ぐことになります

(すでに「.unity-text-element」や「.unity-button」もデフォルトで継承していることがわかりますね。)

これに因って、ボタンは.myStyleで定義した設定(背景色、枠線の色、枠線の幅)に関してだけ上書きされました。

Prefabのオーバーライドと同じですね。

ちなみにUI Builderでも下の部分を引っ張り出せば、.xamlや.ussのコードを見ることができます。
UI Builderで編集した内容が即座に反映されるので、xamlやcssのコードと各設定がどんなふうに対応しているのかがわかりやすく、安心感があります。