UnityでUI Toolkitを使って枠と角丸を持ったカードを作る
概要
最近Unityの勉強をしている者です。ShaderGraphで枠を作ったり9-sliceを使って角丸を作ったりということをしてuGUIで呼び出す、みたいなことをしていましたが、Unityが推進しているUI Toolkitを使えばすごく簡単にこれらの要素を持ったカードデザインを作ることができたので紹介します。
検索してみると、UXMLをメインに使ったサンプルはあったので、USSを使った方法について記載します。
手順
必要なコンポーネントの追加
大体の流れは、USSファイルを使って各部分のデザインについて定義し、UXMLファイルはそれを並べるような感じ。
- ヒエラルキービューで、
UI Toolkit > UI Documentを追加 - プロジェクトビューで、
Create > UI Toolkit > UI Documentを追加(UXMLファイル) - プロジェクトビューで、
Create > UI Toolkit > Style Sheetを追加(USSファイル)
USSファイルの編集
USSファイルを以下のように編集する。(作成時のVisualElement{}は削除する)
.card {
width: 200px;
height: 280px;
background-color: rgb(240, 230, 210);
border-width: 3px;
border-color: rgb(80, 60, 40);
border-radius: 10px;
padding: 10px;
transition-duration: 0.3s;
}
.card:hover {
scale: 1.05;
border-color: rgb(255, 215, 0);
}
.card-header {
flex-direction: row;
justify-content: space-between;
margin-bottom: 5px;
}
.card-title {
font-size: 18px;
-unity-font-style: bold;
color: rgb(40, 30, 20);
}
.card-cost {
font-size: 20px;
-unity-font-style: bold;
color: rgb(200, 100, 0);
background-color: rgb(255, 220, 150);
border-radius: 50%;
width: 30px;
height: 30px;
-unity-text-align: middle-center;
}
.card-image {
height: 120px;
background-color: rgb(200, 190, 170);
border-radius: 5px;
margin-bottom: 10px;
align-items: center;
justify-content: center;
}
.card-icon {
font-size: 60px;
}
.card-description {
min-height: 60px;
background-color: rgb(255, 250, 240);
padding: 5px;
border-radius: 5px;
margin-bottom: 10px;
}
.description-text {
font-size: 12px;
white-space: normal;
color: rgb(60, 50, 40);
}
.card-stats {
flex-direction: row;
justify-content: space-around;
}
.stat {
font-size: 14px;
-unity-font-style: bold;
color: rgb(100, 50, 0);
}
UXMLの編集
作成したUXMLファイルをダブルクリックすると、以下の添付画像のような編集画面が開く(この時点では添付画像のようなカードは出ない)。

なお、Unityのプロジェクトビューの、UXMLファイル以下のinlineStyleからUXMLファイルの中身のコードの閲覧が可能。
ここから、このファイルを以下のように編集する。
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<Style src="project://database/Assets/Game/Dev/CardElement.uss?fileID=7433441132597879392&guid=3485345876ed54bdfb02da78e075e7b1&type=3#CardElement" />
<ui:VisualElement name="card" class="card">
<ui:VisualElement name="card-header" class="card-header">
<ui:Label text="カード名" name="card-title" class="card-title" />
<ui:Label text="5" name="card-cost" class="card-cost" />
</ui:VisualElement>
<ui:VisualElement name="card-image" class="card-image">
<ui:Label text="🎴" class="card-icon" />
</ui:VisualElement>
<ui:VisualElement name="card-description" class="card-description">
<ui:Label text="カードの説明文がここに入ります" name="description-text" class="description-text" />
</ui:VisualElement>
<ui:VisualElement name="card-stats" class="card-stats">
<ui:Label text="ATK: 3" name="attack-stat" class="stat" />
<ui:Label text="DEF: 2" name="defense-stat" class="stat" />
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>
これは(多分)Claude4.5とかGPT5に任せれば直接書いてくれそうでもあるが、GUI上から確認しながら編集することも可能。
これのためには例えば、上記の添付画像の、左のパネルのLibraryの中にあるVisual Elementをダブルクリックすることで、単純な矩形を追加できる(文字の場合はLabel)。
枠・角丸をつける
UXMLファイルのGUIによる編集時、Visual ElementをダブルクリックしてUI Documentのヒエラルキーに追加すると、以下の画像のようなインスペクタが確認できる。

ここのBorderのWidth, Radiusを編集することで枠・角丸をつけることができる。
UXMLファイル・スクリプトのアタッチ
最初に追加したヒエラルキービューのUI Documentに対し、Source Assetのところに作成したUXMLファイルをアタッチします。
続いて、以下のスクリプトをアタッチします。
using UnityEngine;
using UnityEngine.UIElements;
public class CardController : MonoBehaviour
{
[Header("Card Data")]
[SerializeField] private string cardTitle = "Fireball";
[SerializeField] private int cardCost = 5;
[SerializeField] private string cardDescription = "Deals damage to all enemies.";
[SerializeField] private int attackValue = 3;
[SerializeField] private int defenseValue = 2;
private UIDocument uiDocument;
private VisualElement root;
void OnEnable()
{
uiDocument = GetComponent<UIDocument>();
root = uiDocument.rootVisualElement;
// Q=queryのことで、VisualElementの中から特定の名前を持つ要素を取得する
var titleLabel = root.Q<Label>("card-title");
var costLabel = root.Q<Label>("card-cost");
var descriptionLabel = root.Q<Label>("description-text");
var attackLabel = root.Q<Label>("attack-stat");
var defenseLabel = root.Q<Label>("defense-stat");
if (titleLabel != null) titleLabel.text = cardTitle;
if (costLabel != null) costLabel.text = cardCost.ToString();
if (descriptionLabel != null) descriptionLabel.text = cardDescription;
if (attackLabel != null) attackLabel.text = $"ATK: {attackValue}";
if (defenseLabel != null) defenseLabel.text = $"DEF: {defenseValue}";
var card = root.Q<VisualElement>("card");
if (card != null)
{
card.RegisterCallback<ClickEvent>(OnCardClicked);
}
}
void OnDisable()
{
var card = root?.Q<VisualElement>("card");
card?.UnregisterCallback<ClickEvent>(OnCardClicked);
}
private void OnCardClicked(ClickEvent evt)
{
Debug.Log($"Card '{cardTitle}' clicked!");
}
public void UpdateCardData(string title, int cost, string description, int attack, int defense)
{
cardTitle = title;
cardCost = cost;
cardDescription = description;
attackValue = attack;
defenseValue = defense;
if (root != null)
{
root.Q<Label>("card-title").text = cardTitle;
root.Q<Label>("card-cost").text = cardCost.ToString();
root.Q<Label>("description-text").text = cardDescription;
root.Q<Label>("attack-stat").text = $"ATK: {attackValue}";
root.Q<Label>("defense-stat").text = $"DEF: {defenseValue}";
}
}
}
これにより、以下のようなインスペクタの表示になればOKで、Gameビューにカードが表示されるようになりました。


終わりに
UI Toolkitは気になっていたものの、uGUIでなんとかはなるからいいかと思っていました。
ただ、調べてみるとすごくシンプルで、面倒だったところが簡単になったことだけではなく、cssライクな文法だからこそコーディングエージェントの力を発揮できる場所である点がいいなと思いました。
他にも、カードを作る時のドキュメントもあるようです(英語版のみ)。これらも参考になりそうだと思いました。
Discussion