🐷

UnityでUI Toolkitを使って枠と角丸を持ったカードを作る

に公開

概要

最近Unityの勉強をしている者です。ShaderGraphで枠を作ったり9-sliceを使って角丸を作ったりということをしてuGUIで呼び出す、みたいなことをしていましたが、Unityが推進しているUI Toolkitを使えばすごく簡単にこれらの要素を持ったカードデザインを作ることができたので紹介します。
検索してみると、UXMLをメインに使ったサンプルはあったので、USSを使った方法について記載します。

手順

必要なコンポーネントの追加

大体の流れは、USSファイルを使って各部分のデザインについて定義し、UXMLファイルはそれを並べるような感じ。

  1. ヒエラルキービューで、UI Toolkit > UI Documentを追加
  2. プロジェクトビューで、Create > UI Toolkit > UI Documentを追加(UXMLファイル)
  3. プロジェクトビューで、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&amp;guid=3485345876ed54bdfb02da78e075e7b1&amp;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ライクな文法だからこそコーディングエージェントの力を発揮できる場所である点がいいなと思いました。

他にも、カードを作る時のドキュメントもあるようです(英語版のみ)。これらも参考になりそうだと思いました。
https://docs.unity3d.com/6000.2/Documentation/Manual/UIE-encapsulate-uxml-with-logic.html?utm_source=chatgpt.com

Discussion