このページでは、UI Toolkit を使用して簡単なキャラクター選択画面を設定する手順を説明します。UI エレメントとテンプレートの作成、シーンの設定、スクリプトロジックを UI に適用する方法について説明します。このガイドでは、USS によるスタイリングはカバーせず、デフォルトのスタイルとテーマのみを使用します。
このガイドの最終的なソースコードは、このページの 下の方 にあります。
説明項目 UI Builder、ListView、Label、PanelSettings、UIDocument、選択処理
このガイドでは、以下の手順で説明しています。
最終的な UI 画面は、2 つの個別の UI テンプレート (UXML) で構成されています。メインビューテンプレートには、キャラクター名の入ったリスト、選択したキャラクターの詳細を表示するための小さなパネル、ボタンが含まれています。このセクションでは、UI Builder を使用してこのテンプレートを設定します。
ノート: UI Builder を使い慣れていて、このステップを飛ばしたい場合は、このページの下にある MainView の UXML コードをコピーして、新しいファイルに直接貼り付けることができます。Assets/UI/MainView.uxml という名前で保存してください。
メニュー Window > UI Toolkit > UI Builder から、UI Builder ウィンドウを開きます。ビューポートの左上にあるファイルメニューを使用して、新しい UXML ドキュメントを作成します。
ゲームの UI を開発するときは、UI Builder のビューポートの右上にある Unity Default Runtime Theme
を常に選択します。エディターとランタイムのテーマではデフォルトのフォントサイズと色が異なるため、レイアウトに影響が出ます。
Hierarchy で新しい UXML ファイルを選択し、Match Game View のチェックボックスを有効にします。Unity エディターを横向きの解像度に設定していない場合は、設定が必要なことがあります。
いよいよ UI 要素を作成します。 Library から Hierarchy にドラッグして、新しい VisualElement を作成します。
新しい要素は、画面全体を覆う必要があるため、flex-grow
プロパティを 1 に設定する必要があります。Hierarchy から要素を選択し、右側の Inspector で Flex と書かれた折りたたみ部分を探します。Grow の値を 0 から 1 に変更します。
この VisualElement のすべての子要素を画面の中央に配置するには、VisualElement の Align プロパティを変更します。 Align Items と Justify Content の両方を、center (中央) に設定する必要があります。
最後に、Background > Color で背景色を選択します。このステップは必須ではありません。この例では、#732526
の色を使用しています。
次に、既存の VisualElement の下に新しい VisualElement を作成します。これは、UI の左側と右側のセクションの親コンテナになります。
この新しい要素の flex-direction
プロパティを row
(行) に設定します (デフォルトでは列になっています)。また、高さを 350 ピクセルに固定する必要があります。
現在の UI はこのように表示されるはずです。ゲームビュー の解像度やアスペクト比によって、画面表示が異なる場合があることに注意してください。
キャラクター名のリストを作成するには、ListView コントロールを Library から選択し、先ほど作成した VisualElement の下に子要素として加えます。この要素を選択し、Inspector で CharacterList
という名前を割り当てます。これは、後でコントローラースクリプトからこのリストにアクセスするために必要です。
リストの幅を 230 ピクセルに固定します。また、これから作成する次の要素までの距離を確保するために、右側に 6 ピクセルの幅のマージンを与えます。
また、リストの背景色を割り当て、丸みを帯びた境界線を設定することができます。このガイドでは、背景に #6E3925
を、境界線の色に #311A11
を使用し、境界線の幅を 4px、半径を 15px に設定しています。このステップは必須ではありません。
CharacterList
と同じ親に、新しい VisualElement を追加します。これには、キャラクター詳細パネルとボタンが含まれます。 Align 折りたたみの下で、Align Items の設定を flex-end
に、Justify Content の設定を space-between
に変更します。
この新しいコンテナに、新しい VisualElement を加えます。これがキャラクター詳細パネルになります。ユーザーが左のリストからキャラクターを選択すると、そのキャラクターの画像、名前、クラスが表示されます。
要素に固定幅 276 ピクセルを設定し、Align Items と Justify Content を center (中央) に切り替えます。また、要素に 8 ピクセル幅のパディングを加えます。これにより、子要素はコンテナの境界から最小限の距離を保つことができます。
背景色を #AA5939
に、境界色を #311A11
に、境界線幅 4 ピクセル、半径 15 ピクセルでパネルのスタイルを設定します。このステップは必須ではありません。
これで、UI レイアウトは以下の画像のようになります。
次に、キャラクターの詳細に、個々の UI コントロールを加えます。まず、キャラクターの画像です。これは、背景のフレームと前景の画像の 2 つの要素で構成されています。
まず、背景フレーム用のキャラクター詳細コンテナに、新しい VisualElement を加えます。固定サイズ 120x120 ピクセル、パディング 4 ピクセルを割り当て、含まれる画像が境界に直接触れないようにします。
幅 2 ピクセル、半径 15 ピクセルのボーダーで、色は #311A11
、背景色は #FF8554
で要素のスタイルを設定します。代わりに、独自の色やスタイルを自由に適用することができます。
実際の画像は、先ほど作成したフレームの子として、新しい VisualElement を加えます。名前は CharacterPortrait
とし、後でコントローラースクリプトの中でアクセスできるようにします。
Flex > Grow を 1 に設定します。そうすれば、画像は利用可能なスペースをすべて利用します。また、「 Background > Scale Mode 」のスケーリングモードを「 scale-to-fit
」に変更することを確認します。これにより、正しいアスペクト比を維持したまま、要素のサイズに合わせて画像を拡大または縮小することができます。
次に、選択したキャラクターの名前とクラスを表示するために後で使用する 2 つのラベルコントロールをキャラクター詳細コンテナに加えます。これらを CharacterName
と CharacterClass
と名付けます。
クラスよりもキャラクターの名前を目立たせるには、そのラベルのフォントサイズを 18 に変更し、スタイルを B (太字) に設定します。
UI 画面は下図のように表示されます。
最後に、右側の UI コンテナに Button コントロールを追加します。後にこのボタンにコントローラースクリプトでアクセスし、キャラクターが選択されたときや選択解除されたときに有効または無効にします。ボタンの名前は SelectCharButton
とし、固定幅を 150 ピクセルにします。また、ボタンのラベルテキストを Select Character
に設定します。
ボタンのスタイルは、背景色を #FF8554
に、境界色を #311A11
に、境界線幅 2 ピクセルに設定します。このステップは必須ではありません。
完成したメインビューは、以下の画像のように表示されます。
UXML テンプレートを Assets/UI/MainView.uxml という名前で保存します。 また、このテンプレートの最終的な UXML コード は、ページの下の方に記載されています。
このセクションでは、前セクションで作成した UI テンプレートをランタイムにゲームにロードして表示する方法について学びます。
まず始めに、PanelSettings アセットを作成する必要があります。このアセットで、スケーリングモードやレンダリング順序など、画面の設定を定義します。また、UI Toolkit Debugger に表示される UI の名前もこのアセットで決定されます。
Project ビューで右クリックし、新しい Panel Settings Asset
を作成します。Create > UI Toolkit > Panel Settings Asset を選択します。新しく作成したファイルに GameUI_Panel
という名前を付けます。
このガイドでは、すべての設定をデフォルト値のままにしておくことができます。
前セクションのメインビュー UI テンプレートを表示するには、シーン内に新しいゲームオブジェクトを作成する必要があります。それに、UIDocument コンポーネントをアタッチします。
Unity が再生モードに入ると、UIDocument
は割り当てられた VisualTreeAsset
を自動的にロードします。VisualTreeAsset
は、UXML テンプレートです。MainView.uxml
と、新しい GameUI_Panel
パネル設定の両方をコンポーネントに割り当てます。
ノート: UI Document コンポーネントに PanelSettings
アセットを割り当てない場合は、自動的にプロジェクトを検索し、最初に見つかった Panel Settings アセットを自動的に使用します。アセット名を変更したり移動したりする場合は、この点に注意してください。
Unity エディターで再生モードに入り、ゲームビューに表示される UI を確認できるようになりました。
ノート: シーン内に複数の UI Document がある場合、同じパネル設定アセットをすべてに割り当てることができます。これにより、すべての UI が同じパネルに描画されるようになり、パフォーマンスが最適化されます。
このセクションでは、UI のキャラクターリストにデータを入力するためのサンプルデータを作成します。
キャラクターリストには、キャラクター名、クラス、ポートレート画像を保持するシンプルなクラスが必要です。 新しい ScriptableObject スクリプト Assets/Scripts/CharacterData.cs を作成し、次のコードをファイルに貼り付けてください。
using UnityEngine;
public enum ECharacterClass
{
Knight, Ranger, Wizard
}
[CreateAssetMenu]
public class CharacterData : ScriptableObject
{
public string m_CharacterName;
public ECharacterClass m_Class;
public Sprite m_PortraitImage;
}
[CreateAssetMenu]
属性は、Create メニューに自動的にエントリーを加えます。
Project ビューでフォルダーを右クリックし、新しい ScriptableObject のインスタンスを作成します。
ここで、いくつかの CharacterData
インスタンスを作成し、ランダムなデータで埋める必要があります。これらのインスタンスをすべて Resources/Characters というフォルダーに配置します。後で、このフォルダーからすべてのキャラクターデータを自動的に解析してロードするスクリプトを作成します。
このセクションでは、リスト内の個々のエントリー用の UI テンプレートを作成します。ランタイムに、コントローラースクリプトは各キャラクターに対してこの UI のインスタンスを作成し、リストに追加します。 キャラクターリストのエントリーの UI は、色のついた背景フレームとキャラクター名で構成されています。
ノート: このステップを飛ばしたい場合は、このページの下にある list entry の UXML コードをコピーして、新しいファイルに直接貼り付けることができます。Assets/UI/ListEntry.uxml という名前で保存してください。
メニュー Window > UI Toolkit > UI Builder から、UI Builder ウィンドウを開きます。 File > New を選択して、新しい UXML テンプレートを作成します。
背景に VisualElement を追加し、高さを 41 px に固定します。エントリー内のテキストは左寄せにして要素の中央に配置する必要があるので、Align 折りたたみ部分を開き、Align Items から Left (左)、 Justify Content を center (中央) に設定します。 また、左パディングを 10 px に設定し、ラベルがフレームの左境界線から最小限の距離を保つようにします。
背景色を #AA5939
、境界線幅 2 ピクセル、半径 15 ピクセル、境界色を #311A11
で、パネルのスタイルを設定します。このステップは必須ではありません。
既存の VisualElement の子としてラベルを追加し、その名前を CharacterName
とします。これは、後でコントローラースクリプトでアクセスできるようにするためです。Font Style を B (太字) に、フォントサイズを 18 に設定します。
UXML テンプレートを Assets/UI/ListEntry.uxml という名前で保存します。 また、このテンプレートの最終的な UXML コード は、ページの下の方に記載されています。
このセクションでは、リストエントリーのコントローラースクリプトを作成します。このスクリプトの目的は、リストエントリーの UI にキャラクターインスタンスのデータを表示することです。キャラクター名のラベルにアクセスし、指定したキャラクターインスタンスの名前を表示するように設定する必要があります。
新規スクリプト Assets/Scripts/UI/CharacterListEntryController.cs を作成し、以下のコードを貼り付けます。
using UnityEngine.UIElements;
public class CharacterListEntryController
{
Label m_NameLabel;
public void SetVisualElement(VisualElement visualElement)
{
m_NameLabel = visualElement.Q<Label>("CharacterName");
}
public void SetCharacterData(CharacterData characterData)
{
m_NameLabel.text = characterData.m_CharacterName;
}
}
このクラスには 2 つの関数があり、どちらも Set
関数です。
SetVisualElement(VisualElement visualElement)
この関数は、前のセクションで作成した ListEntry
UI テンプレートのインスタンスであるビジュアル要素を受け取ります。メインビューコントローラーがこのインスタンスを作成します。この関数の目的は、UI 要素内のキャラクター名ラベルへの参照を取得することです。
SetCharacterData(CharacterData characterData)
この関数は、このリスト要素が表示する名前を持つキャラクターを取得します。ListView
の要素リストはプールされて再利用されるため、どのキャラクターのデータを表示するかを変更するために Set
関数が必要です。
CharacterListEntry
クラスは、MonoBehaviour
ではないことに注意してください。UI Toolkit のビジュアル要素はゲームオブジェクトではないので、コンポーネントをアタッチすることはできません。代わりに、このクラスは、次のセクションで、userData
プロパティにアタッチされます。
ここでは、メインビューのキャラクターリスト用のコントローラースクリプトと、それをインスタンス化してビジュアルツリーに割り当てる MonoBehaviour スクリプトを作成します。
まず、Assets/Scripts/UI/CharacterListController.cs の下に新しいスクリプトを作成し、次のコードを貼り付けます。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class CharacterListController
{
public void InitializeCharacterList(VisualElement root, VisualTreeAsset listElementTemplate)
{
}
}
InitializeCharacterList()
メソッドを後で入力しますが、今は空のメソッドを追加しておくことが重要です。次のセクションでそれを呼び出すことができるようにするためです。
コントローラースクリプトをメインビューにアタッチ
CharacterListEntryController
と同様に、 CharacterListController
は MonoBehaviour
ではないので、別の方法でビジュアルツリーにアタッチする必要があります。
UIDocument
と同じゲームオブジェクトにアタッチできる MonoBehaviour スクリプトを作成する必要があります。これにより、CharacterListController
をインスタンス化し、ビジュアルツリーにアタッチします。
新規スクリプト Assets/Scripts/UI/MainView.cs を作成し、以下のコードを貼り付けます。
using UnityEngine;
using UnityEngine.UIElements;
public class MainView : MonoBehaviour
{
[SerializeField]
VisualTreeAsset m_ListEntryTemplate;
void OnEnable()
{
// UXML は、すでに UIDocument component コンポーネントによってインスタンス化済み
var uiDocument = GetComponent<UIDocument>();
// キャラクターリストコントローラーを初期化
var characterListController = new CharacterListController();
characterListController.InitializeCharacterList(uiDocument.rootVisualElement, m_ListEntryTemplate);
}
}
Unity エディターで、UIDocument
があるのと同じゲームオブジェクトに、このスクリプトをアタッチします。ListEntry.uxml
を List Entry Template プロパティに割り当てます。
MainView UXML のインスタンス化は、同じゲームオブジェクトの UIDocument
コンポーネントで自動的に行われるため、スクリプトコンポーネントで行う必要はありません。MainView
スクリプトは UIDocument コンポーネントにアクセスし、すでにインスタンス化されているビジュアルツリーの参照を取得します。次に、CharacterListController
のインスタンスを作成し、ビジュアルツリーのルート要素と、個々のリスト要素に使用される UXML テンプレートを渡します。
ノート: UI が再ロードされると、UIDocument
コンポーネントを含む同じゲームオブジェクト上の関連する MonoBehaviour コンポーネントが再ロード前に無効になり、再ロード後に再び有効になります。したがって、これらの MonoBehaviour の OnEnable
と OnDisable
メソッドに UI と相互作用するコードを配置するのが、効率良い方法です。
すべてのキャラクターデータインスタンスを列挙
コントローラースクリプトに最初に加える機能は、先に作成したキャラクターデータのインスタンスをすべて列挙する関数です。これらは、リストを埋めるために使用されます。
以下のコードを CharacterListController
クラスにコピーしてください。
List<CharacterData> m_AllCharacters;
void EnumerateAllCharacters()
{
m_AllCharacters = new List<CharacterData>();
m_AllCharacters.AddRange(Resources.LoadAll<CharacterData>("Characters"));
}
ノート: このコードは、キャラクターインスタンスを Resources/Characters フォルダーに作成したと想定しています。別のフォルダーにキャラクターを配置した場合は、フォルダー名を適宜調整する必要があります。
ここで、初期化中に EnumerateAllCharacter
メソッドを呼び出す必要があります。 InitializeCharacterList
メソッドの先頭にその呼び出しを加えてください。
public void InitializeCharacterList(VisualElement root, VisualTreeAsset listElementTemplate)
{
EnumerateAllCharacters();
}
UI 要素への参照を取得
このセクションでは、InitializeCharacterList
メソッドのコンテンツを記入します。最初に行う必要があるのは、情報を表示するためにアクセスが必要なすべての UI コントロールへの参照を個々に取得することです。名前、USS クラス、型、またはこれらの組み合わせによって個々の UI コントロールを取得するには API の UQuery ファミリーを使用します。
CharacterListController
クラス内のコードを以下のコードで拡張します。
// リストエントリー用 UXML テンプレート
VisualTreeAsset m_ListEntryTemplate;
// UI 要素参照
ListView m_CharacterList;
Label m_CharClassLabel;
Label m_CharNameLabel;
VisualElement m_CharPortrait;
Button m_SelectCharButton;
public void InitializeCharacterList(VisualElement root, VisualTreeAsset listElementTemplate)
{
EnumerateAllCharacters();
// リストエントリーのテンプレートへの参照を保存
m_ListEntryTemplate = listElementTemplate;
// キャラクターリスト要素への参照を保存
m_CharacterList = root.Q<ListView>("CharacterList");
// 選択されたキャラクターリスト要素への参照を保存
m_CharClassLabel = root.Q<Label>("CharacterClass");
m_CharNameLabel = root.Q<Label>("CharacterName");
m_CharPortrait = root.Q<VisualElement>("CharacterPortrait");
// 選択ボタンへの参照を保存n m_SelectCharButton = root.Q<Button>("SelectCharButton");
}
リストにエントリーを入力
次に、先ほど列挙してロードしたキャラクターを画面のリストに入力する必要があります。そのためには、CharacterListController
クラスの中に FillCharacterList
という新しいメソッドを作成する必要があります。
ListView に要素を入力するには、4 つのステップが必要です。
makeItem
関数を作成bindItem
関数を作成makeItem コールバック関数の目的は、UI を表す小さなビジュアルツリーを 1 つのリストアイテムで作成し、このツリーのルートの VisualElement を返すことです。
この場合、makeItem
コールバックは、リストエントリー用に作成した UXML テンプレートをインスタンス化する必要があります。また、CharacterListEntryController
コントローラースクリプトのインスタンスを作成する必要があります。これは、CharacterData
からのデータで UI を埋める処理を行うものです。
クラス内に FillCharacterList
メソッドを作成し、以下のコードを貼り付けてください。
void FillCharacterList()
{
// リストエントリーの makeItem 関数を設定
m_CharacterList.makeItem = () =>
{
// エントリー用の UXML テンプレートをインスタンス化
var newListEntry = m_ListEntryTemplate.Instantiate();
// データ用のコントローラーをインスタンス化
var newListEntryLogic = new CharacterListEntryController();
// コントローラースクリプトをビジュアル要素に割り当てる
newListEntry.userData = newListEntryLogic;
// コントローラースクリプトを初期化
newListEntryLogic.SetVisualElement(newListEntry);
// インスタンス化されたビジュアルツリーのルートを返す
return newListEntry;
};
makeItem
コールバックの一部として、コントローラースクリプトを、インスタンス化したビジュアル要素の userData
プロパティ内に格納します。これにより、後でスクリプトにアクセスし、リスト要素に異なるキャラクターを割り当てることができます。
// コントローラスクリプトをビジュアル要素に割り当てる
newListEntry.userData = newListEntryLogic;
メモリとパフォーマンスの最適化として、ListView
は、リスト内のエントリーごとに 1 つの要素をインスタンス化するのではなく、リスト要素を再利用します。これは、可視領域を満たすのに十分なビジュアル要素のみを作成し、リストがスクロールされるとそれらをプールして再利用します。
このため、データのインスタンス (この場合は CharacterData
) を個々のリスト要素に紐づけする bindItem コールバックを用意する必要があります。
FillCharacterList
メソッドの下部に以下のコードを追加し、拡張します。
// 特定のリストエントリーに対するバインド関数を設定
m_CharacterList.bindItem = (item, index) =>
{
(item.userData as CharacterListEntryController).SetCharacterData(m_AllCharacters[index]);
};
bindItem
コールバックは、リストエントリーのビジュアルツリーのためのルートビジュアル要素への参照と、データへのインデックスを受け取ります。ビジュアル要素の userData
プロパティに CharacterListEntryController
への参照を保存したので、コードはこれにアクセスして直接CharacterData
を設定できます。
最後に、要素のアイテムの高さを設定し、リストのデータソースへの参照を提供する必要があります。これは、リストに含まれる要素の数を伝えます。
FillCharacterList
メソッドの下部に以下のコードを追加し、拡張します。
// 固定アイテムの高さを設定
m_CharacterList.fixedItemHeight = 45;
// 実際のアイテムのソースリスト/配列を設定
m_CharacterList.itemsSource = m_AllCharacters;
初期化の最後に FillCharacterList
メソッドを呼び出す必要があります。
以下のように、 InitializeCharacterList
メソッドの一番下に呼び出しを追加します。
FillCharacterList();
この時点で 再生モード にすると、キャラクターリストが作成したキャラクターの名前でいっぱいになります。
CharacterListController
スクリプトの最終的な コード は、このガイドの下の方にあります。
ユーザーがキャラクターを選択すると、画面右側のキャラクター詳細欄に、キャラクターの詳細、つまり画像、フルネーム、クラスが表示される必要があります。また、キャラクターを選択すると、選択ボタンが有効になる必要があります。キャラクターが選択されていないときは、再びボタンが無効になるようにします。
なお、リスト内のキャラクターをクリックして選択することはすでに可能です。選択とハイライトの機能は、ListView コントロールの一部です。必要なのは、ユーザーがリストの選択を変更するときに反応するコールバック関数だけです。ListView
コントロールは、この目的のために onSelectionChange
イベントを含んでいます。
InitializeCharacterList
メソッドの最後に以下のコードを加えます。
// アイテムが選択されたときにコールバックを取得するように登録
m_CharacterList.onSelectionChange += OnCharacterSelected;
ここで、上のコードで設定したコールバック関数 OnCharacterSelected
を実装する必要があります。この関数は、リスト内で選択されたすべてのアイテムのリストを受け取ります。ただし、このリストでは 1 つのアイテムしか選択できないため、リストの selectedItem プロパティを使用して、選択されたアイテムに直接アクセスできます。
以下のコードをクラス内にコピーしてください。
void OnCharacterSelected(IEnumerable<object> selectedItems)
{
// ListView から現在選択されているアイテムを直接取得
var selectedCharacter = m_CharacterList.selectedItem as CharacterData;
}
selectedItem
プロパティが null を返す場合があります。これは、何も選択されていない場合、またはユーザーが ESC
キーを押してすべての選択を解除した場合に起こります。このケースは、最初に処理する必要があります。
OnCharacterSelected
メソッドを以下のように拡張します。
void OnCharacterSelected(IEnumerable<object> selectedItems)
{
// ListView から現在選択されているアイテムを直接取得
var selectedCharacter = m_CharacterList.selectedItem as CharacterData;
// 非選択を処理 (Escape ですべて非選択にする)
if (selectedCharacter == null)
{
// クリア
m_CharClassLabel.text = "";
m_CharNameLabel.text = "";
m_CharPortrait.style.backgroundImage = null;
// 選択ボタンを無効にする
m_SelectCharButton.SetEnabled(false);
return;
}
}
選択が有効である場合、UI にキャラクターの詳細を表示する必要があります。クラスの InitializeCharacterList
メソッドで取得した参照を通じて、ラベルとポートレート画像のビジュアル要素にアクセスできます。
以下のコードを OnCharacterSelected
メソッドにコピーします。
// キャラクターの詳細を記入する
m_CharClassLabel.text = selectedCharacter.m_Class.ToString();
m_CharNameLabel.text = selectedCharacter.m_CharacterName;
m_CharPortrait.style.backgroundImage = new StyleBackground(selectedCharacter.m_PortraitImage);
// 選択ボタンを有効にする
m_SelectCharButton.SetEnabled(true);
これで 再生モード に入り、キャラクター選択リストの動作を確認することができます。Escape
キーを押すと、キャラクターの選択を解除できます。
以下に、このガイドで作成したすべてのファイルの完全なソースコードを掲載します。
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<ui:VisualElement style="flex-grow: 1; align-items: center; justify-content: center; background-color: rgb(115, 37, 38);">
<ui:VisualElement style="flex-direction: row; height: 350px;">
<ui:ListView focusable="true" name="CharacterList" style="width: 230px; border-left-color: rgb(49, 26, 17); border-right-color: rgb(49, 26, 17); border-top-color: rgb(49, 26, 17); border-bottom-color: rgb(49, 26, 17); border-left-width: 4px; border-right-width: 4px; border-top-width: 4px; border-bottom-width: 4px; background-color: rgb(110, 57, 37); border-top-left-radius: 15px; border-bottom-left-radius: 15px; border-top-right-radius: 15px; border-bottom-right-radius: 15px; margin-right: 6px;" />
<ui:VisualElement style="justify-content: space-between; align-items: flex-end;">
<ui:VisualElement style="align-items: center; background-color: rgb(170, 89, 57); border-left-width: 4px; border-right-width: 4px; border-top-width: 4px; border-bottom-width: 4px; border-left-color: rgb(49, 26, 17); border-right-color: rgb(49, 26, 17); border-top-color: rgb(49, 26, 17); border-bottom-color: rgb(49, 26, 17); border-top-left-radius: 15px; border-bottom-left-radius: 15px; border-top-right-radius: 15px; border-bottom-right-radius: 15px; width: 276px; justify-content: center; padding-left: 8px; padding-right: 8px; padding-top: 8px; padding-bottom: 8px;">
<ui:VisualElement style="border-left-color: rgb(49, 26, 17); border-right-color: rgb(49, 26, 17); border-top-color: rgb(49, 26, 17); border-bottom-color: rgb(49, 26, 17); border-left-width: 2px; border-right-width: 2px; border-top-width: 2px; border-bottom-width: 2px; height: 120px; width: 120px; border-top-left-radius: 13px; border-bottom-left-radius: 13px; border-top-right-radius: 13px; border-bottom-right-radius: 13px; padding-left: 4px; padding-right: 4px; padding-top: 4px; padding-bottom: 4px; background-color: rgb(255, 133, 84);">
<ui:VisualElement name="CharacterPortrait" style="flex-grow: 1; -unity-background-scale-mode: scale-to-fit;" />
</ui:VisualElement>
<ui:Label text="Label" name="CharacterName" style="-unity-font-style: bold; font-size: 18px;" />
<ui:Label text="Label" display-tooltip-when-elided="true" name="CharacterClass" style="margin-top: 2px; margin-bottom: 8px; padding-top: 0; padding-bottom: 0;" />
</ui:VisualElement>
<ui:Button text="Select Character" display-tooltip-when-elided="true" name="SelectCharButton" style="width: 150px; border-left-color: rgb(49, 26, 17); border-right-color: rgb(49, 26, 17); border-top-color: rgb(49, 26, 17); border-bottom-color: rgb(49, 26, 17); background-color: rgb(255, 133, 84); border-left-width: 2px; border-right-width: 2px; border-top-width: 2px; border-bottom-width: 2px;" />
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<ui:VisualElement style="height: 41px; align-items: flex-start; justify-content: center; padding-left: 10px; background-color: rgba(170, 89, 57, 255); border-left-color: rgba(49, 26, 17, 255); border-right-color: rgba(49, 26, 17, 255); border-top-color: rgba(49, 26, 17, 255); border-bottom-color: rgba(49, 26, 17, 255); border-left-width: 2px; border-right-width: 2px; border-top-width: 2px; border-bottom-width: 2px; border-top-left-radius: 15px; border-bottom-left-radius: 15px; border-top-right-radius: 15px; border-bottom-right-radius: 15px;">
<ui:Label text="Label" display-tooltip-when-elided="true" name="CharacterName" style="-unity-font-style: bold; font-size: 18px;" />
</ui:VisualElement>
</ui:UXML>
using UnityEngine;
public enum ECharacterClass
{
Knight, Ranger, Wizard
}
[CreateAssetMenu]
public class CharacterData : ScriptableObject
{
public string m_CharacterName;
public ECharacterClass m_Class;
public Sprite m_PortraitImage;
}
using UnityEngine.UIElements;
public class CharacterListEntryController
{
Label m_NameLabel;
public void SetVisualElement(VisualElement visualElement)
{
m_NameLabel = visualElement.Q<Label>("CharacterName");
}
public void SetCharacterData(CharacterData characterData)
{
m_NameLabel.text = characterData.m_CharacterName;
}
}
using UnityEngine;
using UnityEngine.UIElements;
public class MainView : MonoBehaviour
{
[SerializeField]
VisualTreeAsset m_ListEntryTemplate;
void OnEnable()
{
// UXML は、すでに UIDocument component コンポーネントによってインスタンス化済み
var uiDocument = GetComponent<UIDocument>();
// キャラクターリストコントローラーを初期化
var characterListController = new CharacterListController();
characterListController.InitializeCharacterList(uiDocument.rootVisualElement, m_ListEntryTemplate);
}
}
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class CharacterListController
{
// リストエントリー用 UXML テンプレート
VisualTreeAsset m_ListEntryTemplate;
// UI 要素の参照
ListView m_CharacterList;
Label m_CharClassLabel;
Label m_CharNameLabel;
VisualElement m_CharPortrait;
Button m_SelectCharButton;
public void InitializeCharacterList(VisualElement root, VisualTreeAsset listElementTemplate)
{
EnumerateAllCharacters();
// リストエントリーのテンプレートへの参照を保存
m_ListEntryTemplate = listElementTemplate;
// キャラクターリスト要素への参照を保存
m_CharacterList = root.Q<ListView>("CharacterList");
// 選択されたキャラクター情報要素への参照を保存
m_CharClassLabel = root.Q<Label>("CharacterClass");
m_CharNameLabel = root.Q<Label>("CharacterName");
m_CharPortrait = root.Q<VisualElement>("CharacterPortrait");
// 選択ボタンへの参照を保存
m_SelectCharButton = root.Q<Button>("SelectCharButton");
FillCharacterList();
// アイテムが選択されたときのコールバックを取得するために登録
m_CharacterList.onSelectionChange += OnCharacterSelected;
}
List<CharacterData> m_AllCharacters;
void EnumerateAllCharacters()
{
m_AllCharacters = new List<CharacterData>();
m_AllCharacters.AddRange(Resources.LoadAll<CharacterData>("Characters"));
}
void FillCharacterList()
{
// リストエントリーに対する make item 関数を設定
m_CharacterList.makeItem = () =>
{
// エントリー用の UXML テンプレートをインスタンス化
var newListEntry = m_ListEntryTemplate.Instantiate();
// データ用のコントローラーをインスタンス化
var newListEntryLogic = new CharacterListEntryController();
// コントローラースクリプトをビジュアル要素に割り当てる
newListEntry.userData = newListEntryLogic;
// コントローラースクリプトを初期化
newListEntryLogic.SetVisualElement(newListEntry);
// インスタンス化されたビジュアルツリーのルートを返す
return newListEntry;
};
// 特定のリストエントリーに対するバインド関数を設定
m_CharacterList.bindItem = (item, index) =>
{
(item.userData as CharacterListEntryController).SetCharacterData(m_AllCharacters[index]);
};
// アイテムの固定の高さを設定
m_CharacterList.fixedItemHeight = 45;
// 実際のアイテムのソースリスト/配列を設定
m_CharacterList.itemsSource = m_AllCharacters;
}
void OnCharacterSelected(IEnumerable<object> selectedItems)
{
// ListView から現在選択されているアイテムを直接取得
var selectedCharacter = m_CharacterList.selectedItem as CharacterData;
// 非選択を処理 (Escape ですべて非選択にする)
if (selectedCharacter == null)
{
// クリア
m_CharClassLabel.text = "";
m_CharNameLabel.text = "";
m_CharPortrait.style.backgroundImage = null;
// 選択ボタンを無効にする
m_SelectCharButton.SetEnabled(false);
return;
}
// キャラクターの詳細を入力
m_CharClassLabel.text = selectedCharacter.m_Class.ToString();
m_CharNameLabel.text = selectedCharacter.m_CharacterName;
m_CharPortrait.style.backgroundImage = new StyleBackground(selectedCharacter.m_PortraitImage);
// 選択ボタンを有効にする
m_SelectCharButton.SetEnabled(true);
}
}