Canvasとアンカー を覚え、Layout Group で並べて、uGUIのUIは一通り作れるようになった。そこへ聞こえてくるのが「これからは UI Toolkit らしい」という声 です。じゃあuGUIで作った知識は無駄になるのか? 全部作り直し?——安心してください。答えは 「置き換え」ではなく「使い分け」 です。
この記事では、UI Toolkitの部品(UIDocument・UXML・USS)の関係から、UI Builderで作った画面をC#から動かす方法、そして本領である 大量リストの仮想化 までを、クエストログ画面を題材に解説します。最後に「uGUIを残すべき場面」も明確にします。
この記事でわかること
- uGUIとUI Toolkitの 使い分けの判断基準
- UIDocument・UXML・USS の役割分担(構造・見た目・振る舞い)
- UI Builderで作った要素を C#から
Q<T>()で掴む- USSクラスの付け外し で状態の見た目を切り替える
- ListViewの仮想化(1000件でも軽いリスト)
- 実践:クエストログ画面を組む
- uGUIを残す場面(World Space・演出・既存資産)
動作確認環境: Unity 2022.3 LTS / Unity 6
uGUIとUI Toolkitは、競合ではない
2つのUIシステムは、生まれも得意分野も違います。
- uGUI はGameObjectベースです。UIの1要素が1つのGameObjectで、Transformで動かせて、パーティクルや3D演出と自由に混ざる。 「ゲームの世界に溶け込むUI」 が得意です
- UI Toolkit はWebライクです。構造(UXML)と見た目(USS)をファイルに分け、要素はGameObjectではない軽量なオブジェクト。 「大量のデータを整然と並べる画面」 が得意で、エディタ拡張のUIもこれで作ります

判断の目安はこうです。 キャラの頭上のHPバー、3D空間の看板、アニメーションと絡む演出UI → uGUI。 インベントリ・ランキング・クエストログのような「表」、設定画面のような「フォーム」、エディタ拡張 → UI Toolkit。1つのゲームの中で両方を使うのは、まったく普通のことです。
部品の関係:UIDocument・UXML・USS
UI Toolkitの画面は、3種類のファイルと1つのコンポーネントでできています。Web開発の経験があれば「HTML・CSS・JavaScript」の関係そのものです。

| 部品 | 役割 | Webでの相当物 |
|---|---|---|
| UXML(.uxml) | 構造:何がどの順で並ぶか | HTML |
| USS(.uss) | 見た目:色・余白・フォント | CSS |
| C# | 振る舞い:クリックで何が起きるか | JavaScript |
| UIDocument | 上記をシーンに接続するコンポーネント | — |
シーン側の準備は、空のGameObjectに UIDocument コンポーネントを付け、作ったUXML(Source Asset)と Panel Settings アセットを割り当てるだけです。Canvasのような階層は要りません——画面の構造はUXMLファイルの中にあります。
UI Builderで作って、C#から掴む
UXMLを手書きする必要はありません。 UI Builder(Window > UI Toolkit > UI Builder)が、uGUIのSceneビューに相当するビジュアルエディタです。左のLibraryからLabelやButtonをドラッグし、右のInspectorで名前とスタイルを整えます。
作った要素をC#から掴むときの合言葉が Q<T>()(Query)です。
using UnityEngine;
using UnityEngine.UIElements;
public class TitleScreen : MonoBehaviour
{
[SerializeField] private UIDocument document;
void OnEnable()
{
// UIの根っこ(rootVisualElement)から、名前で要素を探す
VisualElement root = document.rootVisualElement;
Button startButton = root.Q<Button>("start-button");
Label versionLabel = root.Q<Label>("version-label");
versionLabel.text = "v" + Application.version;
startButton.clicked += OnStartClicked;
}
void OnStartClicked()
{
Debug.Log("ゲーム開始!");
}
}
uGUIとの決定的な違いに気づいたでしょうか。 InspectorでボタンをSerializeFieldにドラッグする配線が消え、名前による検索に変わっています。UIの構造を変えても、名前さえ守ればC#は壊れません。
USSクラスで状態を切り 替える
USSは見た目のルール集です。要素に クラス(.quest-item のような名前札)を付けておき、ルールを紐づけます。
/* QuestLog.uss */
.quest-item {
padding: 6px 12px;
color: rgb(230, 230, 230);
}
/* 達成済みクエストの見た目:クラスを1つ足すだけで切り替わる */
.quest-item--done {
color: rgb(120, 200, 120);
-unity-font-style: italic;
}
/* マウスが乗った時(擬似クラス) */
.quest-item:hover {
background-color: rgba(255, 255, 255, 0.08);
}
C#側は「見た目の詳細」を知らずに、 クラスを付け外しするだけ です。
// 達成状態に応じてクラスを付け外しする(第2引数がtrueなら付く)
questLabel.EnableInClassList("quest-item--done", quest.isDone);
uGUIなら「色を変えるコード」「フォントを変えるコード」をC#に書いていた場面が、 「状態の名前を貼るだけ」 になります。見た目の調整はUSSファイル側で完結し、デザイン変更でC#を触る必要がなくなる——これがUI Toolkitの設計思想の中心です。
イベントと、ListViewの仮想化
イベントは clicked(Button専用の簡易版)と RegisterCallback(汎用)の2系統があります。どちらも 登録したら解除する のは、C#イベント と同じ作法です。
そしてUI Toolkitの本領が ListViewの仮想化 です。

uGUIで1000件のリストを素直に作ると、1000個のGameObjectが生まれて画面外の分まで毎フレーム面倒を見ることになります。ListViewは発想が逆で、 画面に見えている十数行だけを作り、スクロールに合わせて中身を差し替えて使い回します。1000件でも10000件でも、生成されるのは見えている行数分だけです。
使い方は3点セットです。
listView.makeItem = () => new Label(); // 行の器を1つ作る方法
listView.bindItem = (element, index) => // 器にi番目のデータを流し込む方法
{
((Label)element).text = quests[index].title;
};
listView.itemsSource = quests; // データ本体
「器の作り方」と「データの流し込み方」だけ教えれば、生成数の管理と使い回しはListViewが引き受けます。
実践:クエストログ画面を組む
RPGのクエストログ、ソシャゲのミッション一覧、実績画面——「左に一覧、選ぶと詳細」はゲームUIの定番構図です。ListViewの練習台として最適なので、これを組みます。

UXML(UI Builderで組んだ構造。左にリスト、右に詳細):
<ui:UXML xmlns:ui="UnityEngine.UIElements">
<ui:VisualElement name="quest-log" class="quest-log">
<ui:ListView name="quest-list" class="quest-list" />
<ui:Label name="quest-detail" class="quest-detail" text="クエストを選択" />
</ui:VisualElement>
</ui:UXML>
C#(データを流し込み、選択に反応する):
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
[Serializable]
public class Quest
{
public string title;
public string detail;
public bool isDone;
}
public class QuestLogScreen : MonoBehaviour
{
[SerializeField] private UIDocument document;
[SerializeField] private List<Quest> quests = new List<Quest>();
private ListView questList;
private Label questDetail;
void OnEnable()
{
VisualElement root = document.rootVisualElement;
questList = root.Q<ListView>("quest-list");
questDetail = root.Q<Label>("quest-detail");
// 3点セット:器の作り方・流し込み方・データ本体
questList.makeItem = () => new Label();
questList.bindItem = (element, index) =>
{
var label = (Label)element;
label.text = quests[index].title;
label.AddToClassList("quest-item");
// 達成済みなら見た目クラスを付ける(詳細はUSSに任せる)
label.EnableInClassList("quest-item--done", quests[index].isDone);
};
questList.fixedItemHeight = 32;
questList.itemsSource = quests;
// 行を選んだら詳細を出す
questList.selectionChanged += OnQuestSelected;
}
void OnDisable()
{
// 解除はいつもの作法
questList.selectionChanged -= OnQuestSelected;
}
void OnQuestSelected(IEnumerable<object> selection)
{
if (selection.FirstOrDefault() is Quest quest)
{
questDetail.text = quest.title + "\n\n" + quest.detail;
}
}
}
InspectorでQuestを20件ほど登録してPlayしてみてください。一覧が並び、クリックで詳細が切り替わり、達成済みだけ緑のイタリックになります。ここで一度、 Questを1000件に増やしてみてください——スクロールは滑らかなままのはずです。試しにヒエラルキーを見ても、1000個のGameObjectはどこにもありません。それが仮想化です。
もし一覧が空っぽなら、見る場所は2つ。itemsSource を設定する前に Q<ListView> が null を返していないか(UXML側の name とC#の文字列が一致しているか)。そして fixedItemHeight が0のままだと行の高さが計算できず表示されないことがあります。
ポイントは2つ。 C#はデータと状態クラスだけを扱い、見た目はUSSに任せる。 大量リストはListViewの3点セット(makeItem・bindItem・itemsSource)に乗せるだけで仮想化が付いてくる。
uGUIを残す場面
UI Toolkitが便利でも、全部を移す必要はありません。次の場面はuGUIが今も定番です。
- World Space UI: キャラの頭上のHPバー、3D空間に置く看板、VRのUI。UI Toolkitのランタイム対応はスクリーンスペース中心で、ワールド空間はuGUIのWorld Space Canvasの領分です
- 演出と密結合のUI: パーティクルを重ねる、UIそのものをAnimatorで暴れさせる、3Dモデルを混ぜ込む——GameObjectであることが利点になるUI
- 既存資産: 動いているuGUI画面を書き換える理由は、基本ありません。 新しく作る「表とフォーム」からUI Toolkitを試す のが現実的な移行です
お まけ:先に知っておくと良いこと
- 解像度対応はPanel Settingsで: uGUIのCanvas Scalerに相当する設定(Scale ModeのScale With Screen Size相当)はPanel Settingsアセットにあります。基準解像度を決めておけば、リサイズ対応はUSSのパーセント指定と合わせて素直に効きます
- ゲームパッド対応はフォーカスの設計: ボタン間の移動はフォーカスシステムが担います。マウス前提で作ってからパッド対応を足すと苦労するので、パッド対象のゲームなら最初からフォーカス移動を確認しながら組んでください
- エディタ拡張と地続き: ここで覚えたUXML・USS・
Q<T>()は、そのまま エディタ拡張 のUI作りに使えます。ランタイムUIの練習が、開発ツール製作の練習を兼ねます
まとめ
- uGUIとUI Toolkitは 使い分け:世界に溶け込むUIはuGUI、表とフォームと大量リストはUI Toolkit
- 分担は UXML=構造・USS=見た目・C#=振る舞い、つなぐのが UIDocument
- C#からは
Q<T>("name")で掴む。Inspector配線は名前検索に置き換わる - 状態の見た目は USSクラスの付け外し(
EnableInClassList)で切り替える - 大量リストは ListViewの3点セット で仮想化——1000件でもGameObjectは増えない
次にインベントリやランキングのような「表」を作る日が来たら——uGUIで組み始める前に、この記事のクエストログを思い出してください。それがUI Toolkitの出番です。