UIElements は Unity の新しいリテインドモードの UI フレームワークで、現在は Unity 2019.1 のパブリック API として提供されています。現在の形は、Unity エディターの拡張を容易にするツールです。今後のリリースで、ゲーム内サポートやビジュアルオーサリングが追加される予定です。
これまで、Unity でカスタムエディターウィンドウやインスペクターを作成するには、イミディエイトモード API である IMGUI を使用する必要がありました。IMGUI を使用すると、ユーザーインターフェースの作成を簡単に開始できますが、複雑なアプリケーションを作成するときにスケールすることができません。また、ユーザーが現在のフレーム内の任意のタイミングで UI の構造を大幅に変更できるため、システムによるレンダリングの最適化が困難です。さらに、すべての UI が C# で宣言されるため、将来出てくる、視覚的に UI をオーサリングするツールでも C# コードを生成する必要があり、これはやっかいな問題となっています。
リテインドモードの API である UIElements では、開発者がオブジェクトの UI ヒエラルキーを作成すると、システムによってそれがレンダリングされます。このようにして、システムによって描画の内容とタイミングが最適化され、全体的なパフォーマンスが向上します。このパラダイムではほかにも、ヒエラルキーとスタイリングが機能から切り離されます。これにより、より適切に関心の分離が行われ、アーティストとプログラマーの両方がより気楽に UI のオーサリングをできるようになります。
UIElements の基本的なビルディングブロックは VisualElement クラスです。すべての要素は、VisualElement クラスであるか、それを継承したクラスです。個別の VisualElement は、互いの親子関係を設定して、UI ヒエラルキーを形成できます。レイアウトやスタイリングなどのシステムがこのヒエラルキーを走査して、UI を適切に画面にレンダリングします。
エディターには、それぞれの EditorWindow に、ヒエラルキー内最上位の VisualElement を表す rootVisualElement プロパティーがあります。システムに要素のことを知らせ、描画させるには、このルートの子として要素を追加する必要があります。
using UnityEditor; using UnityEngine.UIElements; public class ExampleWindow : EditorWindow { public void OnEnable() { var root = this.rootVisualElement; SliderInt slider = new SliderInt(); root.Add(slider); // スライダーをルートの子として追加する。 } }
その要素がヒエラルキーに存在する限り、開発者からの入力がなくても、要素が継続して、描画、更新、ユーザーイベントの消費を行います。これが、リテインドモードとイミディエイトモードの最も大きな違いです。開発者の側で必要な作業は、処理の内容とタイミングの宣言だけで、フレームごとにレンダリングを管理する必要はありません。
要素の描画を停止するには、このスライダーのように、スタイリングの変更で一時的に非表示にするか、ヒエラルキーから完全に削除します。
// 簡単に動的に非表示/表示する場合... slider.style.display = Display.None; // この要素を使い終わった場合、削除する。 slider.RemoveFromHierarchy();
リテインドモードでは、(UXML を使用して)ヒエラルキーとスタイリング(USS)の宣言を個別のアセットに分離できるドキュメントモデルも利用できます。C# では、組み込みのクエリシステムとイベントシステムを使用して、自分が宣言した UI と機能やデータのバインドだけに注力できます。
ヒエラルキーとスタイリングのアセットを分離すると、視覚的な UI のオーサリングが可能になります。これにより、すべてのユーザーが簡単に Unity で UI を微調整したり、オーサリングしたり、デザインしたりできるようになります。
C# では要素のヒエラルキー全体を組み立てることができます。しかし、スタイルと同様に、ヒエラルキーの大半は UI の使用期間中に大きく変化することがありません。したがって、UXML と呼ばれる個別の XML ベースのアセットにヒエラルキーを定義して、UI をモジュール化することをお勧めします。
タグ名は C# の型に対応しており、VisualElement から継承したユーザー定義型も完全にサポートされています。属性は作成時に新しい要素に設定されます。ネストされたタグは親タグの子になります。
この .uxml アセットは他の Unity アセットと同じようにロードでき、そのプロセスで VisualTreeAsset オブジェクトを構築できます。その後、この VisualTreeAsset を任意の要素の下で、必要なだけインスタンス化(または複製)できます。
var uxml = AssetDatabase.LoadAssetAtPath("Assets/ExampleUI.uxml"); uxml.CloneTree(root); // uxml にルートの子としてタグを作成する。
UXML で作成したばかりの要素の取得は、この後すぐ説明するクエリシステムで行います。
スタイルは、C# でプロパティーを通じて VisualElement に直接設定できます。しかし、ほとんどのスタイルは静的に定義されるので、C# でスタイルの記述を UI ロジックと分離するのが賢明です。UIElements では、USS と呼ばれる Unity 固有のスタイルシートアセットを使用します。USS では、CSS 標準のサブセットを使用しています。CSS でお馴染みのセレクターと同じものを使用してどの要素をどのスタイルにするのかを特定することができますが、スタイル自体はキーと値のペアです。
/* スタイルクラスを使用。*/ .standard-label { padding: 6px; } /* 要素名を使用。*/ #the-label { font-size: 60px; } /* C# 型を使用。*/ Label { color: rgb(68, 255, 93); }
この .uss アセットは他の Unity アセットと同じようにロードでき、そのプロセスで StyleSheet オブジェクトを構築できます。その後、これを目的の要素に割り当てると、その要素とその要素の子にスタイルが自動的に適用されます。後から子を追加した場合も同様にスタイルが適用されます。
var uss = AssetDatabase.LoadAssetAtPath("Assets/ExampleUI.uss"); root.styleSheets.Add(uss);
スタイルは名前属性や C# 型を使用して適用できますが、スタイルの再利用性を高めるために、要素に 1 つ(以上)のスタイルクラスを割り当てて、そのクラスを USS 内のスタイルと一致させることもできます。それらはタグと考えることができます。
// C# でスタイルクラスを割り当てる var label = new Label(); label.AddToClassList("blue-label");
同じ要素に複数のスタイルシートを追加したり、同じ要素に合致する複数のルールを設定したりすることもできます。USS を使用して複雑なオーバーライドルールを設定し、スタイルをできる限り再利用するようにします。共有スタイル(汎用ボタンの色など)を繰り返し利用すると作業が簡単になります。C# の再コンパイルを待つ必要がなくなるのが大きな理由です。スタイルシート(USS)アセットに対する変更は、ファイル保存時にエディターに自動的に適用されます。
UIElements のクエリシステムは UQuery と呼ばれます。これは、名前属性、現在割り当てられているスタイルクラスリスト、および C# の型の組み合わせを使用してヒエラルキー内の要素を検索するという点で、ウェブの jQuery に似ています。
// スタイルクラスと型を使用。 var label = root.Q
動的なヒエラルキーに対してクエリを複数回実行する必要がある場合に再利用しやすいように最適化した、Query オブジェクトを作成することもできます。
// クエリを 1 回作成する。 UQueryBuilderquery = root.Query (classes: "blue-slider"); // 複数回実行して更新された結果を取得する。 query.ForEach(slider => Debug.Log(slider.name));
UIElements にはイベントシステムが含まれています。イベントは通常、特定の要素に送信され、そのイベントが消費されるまで UI ツリーの上下に伝達されますが、この伝達動作はカスタマイズ可能です。MouseMoveEvent などの基本イベントはシステムによって送信され、開発者はそのイベントの受信登録ができます。独自のカスタムユーザーイベントを定義して送信することもできます。
イベントは、UI の状態が変化したり、ユーザーが何らかの操作をしたりしたことを知るための主な方法です。以下の例では、ユーザーがスライダーの値を変更したタイミングを検出し、ラベル要素に新しい値を表示しています。
var label = new Label(); var slider = new SliderInt(); slider.RegisterCallback >(evt => { label.text = evt.newValue.ToString(); });
UI がおかしく表示されたり、画面に存在するべき要素が表示されなかったりする場合には、UIElements Debugger が役立ちます。Chrome や Firefox のウェブサイト用のデバッガーを使用したことがある人にとっては、親しみやすいでしょう。
このデバッガーで UI の要素をデバッグするには、要素の選択を有効にし、要素の上にカーソルを合わせるか、要素を右クリックして、「Inspect」を選択します。デバッガーの左ペインに現在のウィンドウのライブヒエラルキーがすべて表示され、右ペインにスタイルインスペクターが表示されます。このスタイルインスペクターで、要素にどのスタイルが割り当てられているか、各スタイルの値が何(どのスタイルシートのどのセレクター)に由来しているかを調査できます。それから、スタイルの値をライブで追加したり編集したりして、その変更が UI に与える影響を確認することもできます。
現在、ゲーム内 UI に UIElements を使用できるようにするための取り組みを精力的に進めています。さらに、UIElements を中心とした視覚的なワークフローを用意して、C# コーディングをほとんどまたはまったく行わずに機能的な UI をデザイン、作成できるようにする予定です。
その間にも、インスペクター、専用のエディターウィンドウを使用する新しいツール、ツールバーなど、Unity 自体の開発に UIElements を使用する傾向が強まることが予想されます。
IMGUI と uGUI に関しては引き続きメンテナンスを続け、場合によっては改良を加えていきます。近い将来に廃止する予定はありません。そうは言っても、Unity 2019.1 の Unity エディター以降、Unity で UI を作成する方法としては、UIElements が最も幅広くサポートされることになるので、そちらの利用をお勧めします。
まず、Unite LA 2018 の UIElements に関する講演をご覧になることをお勧めします。サンプルプロジェクトをダウンロードしておけば、話の流れに沿って実際の機能を確認できます。また、この講演では IMGUI と UIElements の主な相違点と共通点についても説明しているので、実際の例を通じて UIElements の主な機能の大半を知ることができます。
サンプルプロジェクトは、GitHub からダウンロードできます。
この API の詳細については、Unity 2019.1 マニュアルを参照してください。