27K Views
October 25, 22
スライド概要
UI Toolkitを使用したツール「AssetViewer」の事例をもとに、ランタイムのUI Toolkitを活用した開発手法についてお話します。
AssetViewerは社内で開発を進めているAssetBundle等の動作を確認できるランタイムツールになります。
本ツールを開発した際のUXML・USSの扱い方やランタイムでのUI Toolkitの扱い方等、実践的なUI Toolkitによる開発のお話ができればと考えています。
こんな人におすすめ:
・UI Toolkitを使用している方
・UI Toolkitを使用する予定のある方
・UI Toolkitに興味がある方
受講者が得られる知見:
・UI Toolkitを使用した開発ノウハウ
・ランタイムでのUI Toolkitの活用方法
出演:
篠木 和貴 (株式会社QualiArts)
片岡 佳椰 (株式会社QualiArts)
--
初出: SYNC 2022 #UnitySYNC
https://events.unity3d.jp/sync/
リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。
UI Toolkitを使用した ランタイムツール の開発事例紹介 2022
篠木 和貴 株式会社QualiArts Unityエンジニア 片岡 佳椰 株式会社QualiArts Unityエンジニア
QualiArts ● CyberAgentゲーム&エンターテイメント事業部のうちの1つ ● Unityを用いた3D美少女ゲームの開発やオリジナルIPの企画を行っている
この発表について 今回、QualiArtsでは、UI Toolkitを使用してAssetViewerというランタイムツールを開発しました。 この発表では、UI Toolkitでランタイムツールを作った際に得られた知見の共有として、UI作成フローや覚えておくと便利なTips を紹介します。
AssetViewerについて 実機でAssetBundle等の外部アセットを確認するためのツール 3D、画像、ADV、音声などを実機上で確認可能 今までは各プロジェクトで作られていたものを、プロジェクト横断で汎用的 に使えるものとして開発
UI Toolkitとは Unityの新しいUIフレームワーク エディタUI・ランタイムUIの両方をサポート AssetViewerでは全てのUIをこのUI Toolkitで構築
ランタイムにおけるUI Toolkit Unity 2020.1からサポート Unity 2022時点ではまだ推奨になっていない UIDocumentというコンポーネントをシーンに配置することでUIを描画する
UI作成フロー
UI作成フロー AssetViewerにおけるUI作成フロー 以下の機能を持つボタンを例に説明する ● 二つの編集可能なラベル ● クリックを行った際にイベントを発行
UI作成フロー UI構成要素 1つのUIごとに次の3つのファイルを作成する UXML USS C#クラス
UI作成フロー - UXML UXML まず「UI Builder」と呼ばれるUnity標準のオーサリングツールで構造情報を記述する 構造情報はUXMLファイルへとして保存される 構造 現在の表示
UI作成フロー - UXML UXML 構造情報を記述したUXMLファイルは次のようになる <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False"> <ui:VisualElement name="Root" class="home-button-view button-1"> <ui:Label name="Title" text="Title" /> <ui:Label name="Description" text="機能の説明" /> <ui:VisualElement name="Arrow" /> </ui:VisualElement> </ui:UXML>
UI作成フロー - USS USS 続いて、UI Builderでスタイル情報を記述する スタイル情報はUSSファイルとして保存される スタイル
UI作成フロー - USS USS スタイル情報を記述したUSSファイルは次のようになる .home-button-view { background-color: var(--bgColor2); width: 340px; height: 76px; border-radius: 10px; } .home-button-view #Title { color: var(--fontColor1); font-size: 30px; position: absolute; top: 11px; left: 15px; } .home-button-view #Description { color: var(--fontColor2); font-size: 16px; position: absolute; bottom: 11px; left: 15px; } .home-button-view #Arrow { background-image: url(../Images/Arrow.png); width: 9px; height: 15px; position: absolute; right: 21px; top: 50%; translate: 0 -50%; }
UI作成フロー - USS 共通USS 固有のUSSの他に、共通で適用するUSS(以降、共通USS)を用意している 共通USSによりAssetViewer全体で使用するスタイル情報を集約できる ボタン スライダー ラベル 個別USS 個別USS 個別USS 共通USS
UI作成フロー - USS 共通USSの設定方法 Theme Style Sheetという設定ファイルを用意し、共通USSを指定する UI BuilderでこのTheme Style Sheetを指定することで、共通USSがUI Builderのビューに反映される ランタイムで表示を行う際もこのTheme Style Sheetを指定するようにする Theme Style Sheetを指定 共通USSを指定
UI作成フロー - USS
共通USSの内容の一部
:root {
/* 色 */
--bgColor1: #25283a;
--bgColor2: #363c5d;
--subViewerBgColor: rgba(54, 60, 93, 0.99);
--fontColor1: #ffffff;
--fontColor2: #abb0dc;
--fontColor3: #6d75b7;
--highlightColor: #ffd800;
/* フォント */
--font1: url(../font/Roboto-Medium.ttf);
--font2: url(../font/ZenMaruGothic-Medium.ttf);
}
/**
* Label
*/
.unity-label {
margin: 0;
padding: 1px 2px 0 0;
-unity-font: var(--font1);
-unity-font-definition: var(--font1);
}
「--bgColor1」等の記述は変数となっている
個別のUSSから参照することで色などの共通化を行なっている
UI作成フロー - C#クラス C#クラス 最後に、UIを制御するクラスを作る クラスには基本的に以下の機能を実装する ● UXMLのロード ● UIへのデータセット ● インタラクションの設定
UI作成フロー - C#クラス
C#クラスの内容
namespace Qua.AssetViewer
{
public class HomeButtonView : VisualElement
{
private Label _titleLabel;
private Label _descriptionLabel;
public event Action onClick;
public HomeButtonView()
{
var treeAsset = Utility.LoadTreeAsset("HomeButtonView");
var view = treeAsset.CloneTree();
hierarchy.Add(view);
UXMLのロード
AssetViewerでは独自の仕組みを作っている
_titleLabel = view.Q<Label>("Title");
_descriptionLabel = view.Q<Label>("Description");
_root.AddManipulator(new Clickable(OnClick));
}
}
}
public HomeButtonView(string title, string description) : this()
{
_titleLabel.text = title;
_descriptionLabel.text = description;
}
データのセット
private void OnClick()
{
onClick?.Invoke();
}
インタラクションの設定
UI作成フロー - C#クラス UXMLのロードの詳細 独自のコンテナクラスのインスタンスをAssetViewerのシーンに配置する そのインスペクターにUXMLファイルを登録し、そこからUXMLの参照を取得している 各UIクラス UXMLの 参照を渡す
UI作成フロー IDEでのUXML・USSの記述 UI Builder上では行えない以下の操作は、IDEで直接編集している ● 絶対パスを相対パスに変更 ○ UI Builderでは他のファイルを参照する場合は絶対パスで記述されてしまう
UI作成フロー まとめ ● UI Builderで構造情報を記述してUXMLを作成 ● UI Builderでスタイル情報を記述してUSSを作成 ○ ● C#クラスを作成し、動作を記述 ○ ● 共通のスタイル情報は共通USSに記述 UXMLの参照はコンテナクラスから取得 IDEでのUXML・USSの記述 ○ 絶対パスを相対パスへ変更
UI ToolkitのTips
UI ToolkitのTips - 共通UIのUI Builderでの利用 共通UIのUI Builderでの利用 他のUIの一部として利用できるUIは、UI Builder上で使用できるようにしている UI Builder上で使用するためには以下の手順が必要 ● UI Builder上で配置できるようにする ● UI Builder上でプロパティを設定できるようにする
UI ToolkitのTips - 共通UIのUI Builderでの利用
UI Builder上で配置できるようにする
UxmlFactoryを継承したクラスを宣言する
これによりUI Builderの「Custom Controls」にパーツが表示され、UI Builderで使用できるようになる
namespace Qua.AssetViewer
{
public class HomeButtonView : VisualElement
{
public new class UxmlFactory : UxmlFactory<HomeButtonView, UxmlTraits>
{
}
UI ToolkitのTips - 共通UIのUI Builderでの利用
UI Builder上でプロパティを設定できるようにする
UxmlTraitsを継承したクラスを宣言する
このクラスに、UI Builderで入力された値を受け取る処理を記述する
またUIクラスに対応するゲッターも記述する
詳細はこちら→ https://technote.qualiarts.jp/article/19
namespace Qua.AssetViewer
{
public class HomeButtonView : VisualElement
{
private string TitleLabelText => _titleLabel.text;
private string DescriptionLabelText => _descriptionLabel.text;
public new class UxmlTraits : VisualElement.UxmlTraits
{
private UxmlStringAttributeDescription _titleAttribute = new() { name = "title-label-text", defaultValue = "Title" };
private UxmlStringAttributeDescription _descriptionAttribute = new() { name = "description-label-text", defaultValue = "機能の説明" };
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
var view = ve as HomeButtonView;
view._titleLabel.text = _titleAttribute.GetValueFromBag(bag, cc);
view._descriptionLabel.text = _descriptionAttribute.GetValueFromBag(bag, cc);
}
UI ToolkitのTips - 共通UIのUI Builderでの利用 UI Builder上でプロパティを設定できるようにする UxmlTraitsの宣言により、UI Builder上でプロパティが設定できるようになり、UIをカスタマイズできるようになる プロパティの値を設定
UI ToolkitのTips - インタラクション操作 インタラクション操作 UI ToolkitではUIにマニピュレーターを設定することで、特定のインタラクションの機能を持たせられる 例: button.AddManipulator(new Clickable(OnClick)); マニピュレーターは、画面をタップしたときや離したときなどの各種イベントで行う処理を記述することでインタラクションを定義してい る 独自の実装も可能で、AssetViewerではドラッグ・フリックをするためのマニピュレーターを用意している
UI ToolkitのTips - インタラクション操作 ドラッグ・フリック用のマニピュレーター 主にPointerDown、PointerMove、PointerUpというイベントを使用して実装 PointerDown PointerMove 開始位置の記録 移動量の記録 と ドラッグの発火 PointerUp 移動量がしきい値を 超えていたらフリック発火
UI ToolkitのTips - USSによる見た目の変化 USSによる見た目の変化 UIの見た目はUSSのクラスを利用し変化させている クラスの命名規則はUnity推奨のBEM方式を採用している BEM方式: Block(親要素)__Elements(子要素)--Modifier(修飾)の順に記述する命名方式 /* Block */ .main-logo { } /* Element */ .main-logo__image { } /* Modifier */ .main-logo--small { }
UI ToolkitのTips - USSによる見た目の変化
ロゴUIを小さくする実例
UXML
<ui:VisualElement name="MainLogo" class="main-logo">
<ui:VisualElement class="main-logo__image"></ui:VisualElement>
</ui:VisualElement>
USS
C#
.main-logo {}
var mainLogo = view.Q("MainLogo");
.main-logo__image {
width: 50px;
height: 50px;
}
// 状態クラスを追加する
mainLogo.AddToClassList("main-logo--small");
// 状態クラスを削除する
mainLogo.RemoveFromClassList("main-logo--small");
.main-logo--small {}
.main-logo--small .main-logo__image {
width: 27px;
height: 27px;
}
UI ToolkitのTips - USSによる見た目の変化
.slider-view #Slider {
flex: 1;
margin: 0 5px;
width: 100%;
min-height: auto;
}
標準のUIを修飾する
Unityが用意した標準のUIも独自のUSSで上書きすることで修飾できる
.slider-view #unity-drag-container {
min-width: 20px;
}
デフォルト:
カスタマイズ後:
独自のUSSで
上書き
標準Sliderの構造
.slider-view #unity-tracker {
position: absolute;
left: 0;
right: 0;
background-color: rgb(40, 46, 81);
border-width: 0px;
border-radius: 2px;
height: 4px;
margin: 0;
top: var(--dragger-margin-top);
}
.slider-view #unity-dragger {
position: relative;
background-color: transparent;
border-width: 0;
margin: 0;
width: var(--dragger-size);
height: var(--dragger-size);
top: auto;
}
UI ToolkitのTips - USSによる見た目の変化 Modifierによるアニメーション 対象のクラスにtransitionを設定することでアニメーションの動作を設定できる 対象を押している間にアクティブを表すModifierをクラスとして付けそのときの見た目を指定することで、 簡単にアニメーションを実現できる .button-1 { transition: scale 0.15s ease-out; scale: 1; } .button-1--active { scale: 0.95; }
UI ToolkitのTips - USSによる見た目の変化 PseudoStatesによるアニメーション Unity標準のClickableマニピュレーターを使うと、対象を押している時にPseudoStates.Activeという特殊な状態がその対象 に付与される このとき、クラス名 + :activeに値を設定することでもアニメーションを実現できる .button-1 { transition: scale 0.15s ease-out; scale: 1; } .button-1:active { scale: 0.95; }
最後に
最後に UI Toolkitをランタイムで使用した所感 ● ● ● ● シンプルなUIを作成するのは問題なく行えた UXMLとUSSはコンパイル不要なのでイテレーションが早い 複雑なUI(ゲームUI等)を作成するのはリスクが高いと感じる ○ 現状、uGUIと比べて機能が少ない ■ マスク、カスタムシェーダー ■ ワールド空間に置けない ■ Animatorで制御できない ○ 情報が少なく、問題が起きた際の解決に時間が掛かる UI Toolkitは開発途中の部分が多いため、今後使用していくためには情報のキャッチアップが大切と感じる ○ 弊社ブログ(QualiArts Engineer Blog)でも積極的に情報を発信していく予定なので、是非御覧ください