Unity UI Toolkit Runtime 활용
UI Toolkit이란
섹션 제목: “UI Toolkit이란”UI Toolkit(구 UIElements)은 Unity 2021.2부터 런타임에서 공식 지원되는 UI 시스템입니다. Unity Editor UI와 동일한 기술 기반으로, HTML/CSS와 유사한 UXML/USS를 사용해 UI를 선언적으로 정의합니다.
기존 uGUI 대비 장점:
- UXML: 구조와 코드 분리
- USS: CSS와 유사한 스타일 시트
- 데이터 바인딩 내장
- 에디터/런타임 통일된 API
기본 설정
섹션 제목: “기본 설정”UI Document컴포넌트를 GameObject에 추가.uxml파일을Panel Settings와 함께 연결- C# 스크립트로 루트 요소 접근
using UnityEngine;using UnityEngine.UIElements;
public class HUDController : MonoBehaviour{ private UIDocument _document; private VisualElement _root;
void OnEnable() { _document = GetComponent<UIDocument>(); _root = _document.rootVisualElement;
// UXML에서 정의한 요소 쿼리 var hpBar = _root.Q<ProgressBar>("hp-bar"); var mpBar = _root.Q<ProgressBar>("mp-bar"); var scoreLabel = _root.Q<Label>("score-label"); var settingsBtn = _root.Q<Button>("settings-btn");
settingsBtn.clicked += OnSettingsClicked; }
void OnDisable() { var settingsBtn = _root.Q<Button>("settings-btn"); if (settingsBtn != null) settingsBtn.clicked -= OnSettingsClicked; }
private void OnSettingsClicked() => Debug.Log("Settings opened");}UXML 구조
섹션 제목: “UXML 구조”<!-- Assets/UI/HUD.uxml --><ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
<ui:VisualElement name="hud-root" class="hud-container">
<!-- 체력 / 마나 바 --> <ui:VisualElement name="stat-bars"> <ui:ProgressBar name="hp-bar" title="HP" value="100" high-value="100" class="stat-bar hp-bar" /> <ui:ProgressBar name="mp-bar" title="MP" value="75" high-value="100" class="stat-bar mp-bar" /> </ui:VisualElement>
<!-- 스코어 --> <ui:Label name="score-label" text="Score: 0" class="score" />
<!-- 스킬 슬롯 --> <ui:VisualElement name="skill-slots" class="skill-bar"> <ui:Button name="skill-1" class="skill-slot" /> <ui:Button name="skill-2" class="skill-slot" /> <ui:Button name="skill-3" class="skill-slot" /> <ui:Button name="skill-4" class="skill-slot" /> </ui:VisualElement>
<!-- 설정 버튼 --> <ui:Button name="settings-btn" text="⚙" class="icon-btn" />
</ui:VisualElement></ui:UXML>USS 스타일링
섹션 제목: “USS 스타일링”/* Assets/UI/HUD.uss */
.hud-container { position: absolute; width: 100%; height: 100%; padding: 16px; flex-direction: column; justify-content: space-between;}
.stat-bars { width: 250px; flex-direction: column; gap: 4px;}
.stat-bar { height: 24px; border-radius: 12px; border-width: 2px; border-color: rgba(0, 0, 0, 0.6);}
.hp-bar > .unity-progress-bar__background { background-color: rgba(0, 0, 0, 0.4); border-radius: 12px;}
.hp-bar > .unity-progress-bar__progress { background-color: rgb(220, 50, 50); border-radius: 12px; transition-property: width; transition-duration: 0.3s; transition-timing-function: ease-out;}
.mp-bar > .unity-progress-bar__progress { background-color: rgb(50, 100, 220); border-radius: 12px;}
.score { font-size: 24px; color: white; -unity-font-style: bold; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);}
.skill-bar { flex-direction: row; justify-content: center; gap: 8px; padding-bottom: 16px;}
.skill-slot { width: 64px; height: 64px; border-radius: 8px; background-color: rgba(0, 0, 0, 0.6); border-color: rgba(255, 255, 255, 0.3); border-width: 2px;}
.skill-slot:hover { border-color: rgb(255, 200, 50); scale: 1.05;}동적 UI 업데이트
섹션 제목: “동적 UI 업데이트”public class GameHUD : MonoBehaviour{ private ProgressBar _hpBar; private ProgressBar _mpBar; private Label _scoreLabel; private int _score;
void OnEnable() { var root = GetComponent<UIDocument>().rootVisualElement; _hpBar = root.Q<ProgressBar>("hp-bar"); _mpBar = root.Q<ProgressBar>("mp-bar"); _scoreLabel = root.Q<Label>("score-label"); }
public void SetHP(float current, float max) { _hpBar.highValue = max; _hpBar.value = current;
// HP 비율에 따라 색상 변경 float ratio = current / max; var progress = _hpBar.Q(className: "unity-progress-bar__progress"); if (progress != null) { progress.style.backgroundColor = ratio > 0.5f ? Color.green : ratio > 0.25f ? Color.yellow : Color.red; } }
public void AddScore(int points) { _score += points; _scoreLabel.text = $"Score: {_score:N0}";
// 점수 증가 애니메이션 효과 _scoreLabel.RemoveFromClassList("score-pop"); _scoreLabel.schedule.Execute(() => _scoreLabel.AddToClassList("score-pop")).ExecuteLater(10); }}코드로 UI 동적 생성
섹션 제목: “코드로 UI 동적 생성”// UXML 없이 코드로 UI 생성public class InventoryUI : MonoBehaviour{ [SerializeField] private InventoryData _inventory;
void OnEnable() { var root = GetComponent<UIDocument>().rootVisualElement; BuildInventoryGrid(root); }
void BuildInventoryGrid(VisualElement root) { var grid = new VisualElement(); grid.name = "inventory-grid"; grid.style.flexDirection = FlexDirection.Row; grid.style.flexWrap = Wrap.Wrap;
foreach (var item in _inventory.Items) { var slot = CreateItemSlot(item); grid.Add(slot); }
root.Add(grid); }
VisualElement CreateItemSlot(ItemData item) { var slot = new VisualElement(); slot.AddToClassList("item-slot"); slot.tooltip = item.Description;
var icon = new Image { sprite = item.Icon }; icon.AddToClassList("item-icon");
var count = new Label(item.Count > 1 ? item.Count.ToString() : ""); count.AddToClassList("item-count");
slot.Add(icon); slot.Add(count);
// 클릭 이벤트 slot.RegisterCallback<ClickEvent>(_ => OnItemClicked(item));
// 드래그 앤 드롭 slot.RegisterCallback<MouseDownEvent>(e => { if (e.button == 0) StartDrag(slot, item); });
return slot; }
private void OnItemClicked(ItemData item) => Debug.Log($"Clicked: {item.Name}"); private void StartDrag(VisualElement slot, ItemData item) { /* 드래그 구현 */ }}이벤트 시스템
섹션 제목: “이벤트 시스템”void RegisterEvents(VisualElement root){ var panel = root.Q("settings-panel");
// 마우스 이벤트 panel.RegisterCallback<MouseEnterEvent>(e => panel.style.backgroundColor = new StyleColor(new Color(0, 0, 0, 0.8f)));
panel.RegisterCallback<MouseLeaveEvent>(e => panel.style.backgroundColor = new StyleColor(new Color(0, 0, 0, 0.6f)));
// 키보드 이벤트 (포커스 필요) panel.focusable = true; panel.RegisterCallback<KeyDownEvent>(e => { if (e.keyCode == KeyCode.Escape) panel.style.display = DisplayStyle.None; });
// 포인터 이벤트 (터치 지원) panel.RegisterCallback<PointerDownEvent>(e => { Debug.Log($"Pointer down at {e.position}"); e.StopPropagation(); // 이벤트 버블링 중단 });}| 개념 | 역할 |
|---|---|
UIDocument | UXML 파일과 씬을 연결 |
VisualElement | 모든 UI 요소의 기반 클래스 |
UXML | HTML과 유사한 UI 구조 선언 |
USS | CSS와 유사한 스타일 정의 |
Q<T>("name") | 요소 쿼리 (타입 + 이름) |
RegisterCallback<T> | 이벤트 리스너 등록 |
UI Toolkit은 선언적 구조와 스타일 분리로 복잡한 UI를 체계적으로 관리할 수 있게 합니다. UGUI의 GameObject 기반 방식보다 대규모 UI 시스템에서 유리합니다.