서비스
교육 철학

UI 시스템

Abstract

📌
UI 시스템은 화면 하나(HUD, 일시정지 메뉴, 인벤토리 …)를 폼(Form) 이라는 단위로 다룹니다. OpenUIForm 으로 열고 CloseUIForm 으로 닫으며, 닫힌 폼은 파괴되지 않고 풀에 남아 다음에 다시 쓰입니다. 폼끼리 겹쳤을 때 "가려진 폼은 멈춘다" 같은 규칙도 프레임워크가 처리합니다.
실무에서 필요한 순간
•
화면이 열 개를 넘어가면서 "지금 뭐가 떠 있지?"를 코드로 추적하기 어려워질 때
•
팝업 위에 팝업이 뜨는 구조에서 아래 화면의 입력·갱신을 멈춰야 할 때
•
자주 여닫는 창을 매번 Instantiate 하고 싶지 않을 때
ToyboxNightmare 에서의 실제 사용
// ProcedureMain — 게임 시작 시 HUD 와 일시정지 메뉴를 연다 UIComponent ui = GameEntry.GetComponent<UIComponent>(); ui.OpenUIForm("HUDForm", "Default"); // (Addressables 주소, UI 그룹) ui.OpenUIForm("PauseMenuForm", "Default");
C#
복사
// HUDForm — 폼 로직은 UIFormLogic 을 상속한다 public class HUDForm : UIFormLogic { protected override void OnInit(object userData) { /* 자식 참조 캐싱 — 인스턴스당 1회 */ } protected override void OnOpen(object userData) { /* 이벤트 구독, 표시값 초기화 */ } protected override void OnClose(bool isShutdown, object userData) { /* 구독 해제 */ } }
C#
복사
폼
역할
Canvas Sorting Order
HUDForm
체력 바, 점수, 무기 아이콘, 아군 게이지
0
PauseMenuForm
ESC 로 여닫는 일시정지 메뉴, 볼륨 슬라이더
100
엔티티와 정반대인 규칙 하나
UI 폼 프리팹에는 UIFormLogic 스크립트를 반드시 미리 붙여 둡니다. 엔티티는 로직을 런타임에 붙이지만, UI 폼은 프리팹에 붙어 있는 것을 GetComponent 로 찾습니다. 빠뜨리면 에러 없이 OnInit / OnOpen 이 하나도 불리지 않습니다.
확장하려면
•
새 화면 = UIFormLogic 상속 클래스 + 프리팹(루트에 로직 부착) + Addressables 등록
•
팝업·시스템 알림처럼 층이 필요해지면 UI 그룹을 늘린다 (AddUIGroup("Popup", 10))
•
열기 실패는 화면에 아무 표시가 없다. OpenUIFormFailureEventArgs 를 구독해 로그를 남긴다 (예제의 ProcedureMain 참고)
따라 만들어 보려면 07. HUD 와 일시정지 — 이벤트로 잇는 UI 을 보세요.
⚠️
이 에디션에서 다른 점
•
에셋 이름은 프로젝트 경로가 아니라 Addressables 주소입니다.
•
훅은 protected override 로 오버라이드합니다. 프레임워크가 별도 어셈블리라 protected override 는 컴파일 에러(CS0507)입니다.
•
기본 그룹 헬퍼 DefaultUIGroupHelper.SetDepth 는 빈 구현입니다. 그룹 depth 만으로는 화면 순서가 바뀌지 않으므로, Canvas 의 Sorting Order 를 직접 주거나 UIGroupHelperBase 를 상속한 헬퍼로 교체해야 합니다.
•
OnInit 은 인스턴스가 새로 만들어질 때 한 번만 불립니다. 풀에서 다시 꺼낼 때는 OnOpen 만 불립니다.

UI 시스템

관련 소스 파일
•
Scripts/Runtime/Base/GameEntry.cs
•
Scripts/Runtime/Entity/Entity.cs
•
Scripts/Runtime/Entity/EntityComponent.cs
•
Scripts/Runtime/Entity/EntityLogic.cs
•
Scripts/Runtime/Scene/SceneComponent.cs
•
Scripts/Runtime/Sound/SoundComponent.cs
•
Scripts/Runtime/UI/UIComponent.cs
•
Scripts/Runtime/UI/UIForm.cs
•
Scripts/Runtime/UI/UIFormLogic.cs
UI 시스템은 Game Framework에서 사용자 인터페이스를 관리하는 역할을 하며, UI 폼(창, 패널 등)을 그 수명주기 전반에 걸쳐 처리하기 위한 구조화된 접근 방식을 제공합니다. 이는 UI 요소를 생성, 표시, 조직, 제거하는 데 있어 적절한 리소스 관리를 갖춘 강력한 아키텍처를 제공합니다.
엔티티 관리에 대한 내용은 Entity System, 씬 관리에 대한 내용은 Scene Management를 참고하세요.

아키텍처 개요

UI 시스템은 Game Framework의 컴포넌트 기반 아키텍처를 따르며, 프레임워크 계층과 Unity 구현 간의 명확한 분리를 가지고 있습니다. UI 폼을 그룹으로 조직하고, 표시 순서, 가시성, 그리고 수명주기를 관리합니다.
출처:
•
Scripts/Runtime/UI/UIComponent.cs 22-146
•
Scripts/Runtime/Base/GameEntry.cs 16-57

핵심 컴포넌트

UIComponent

UIComponent는 UI 관련 작업에 대한 주요 진입점입니다. GameEntry에 등록되어 있으며, 다음과 같은 메서드를 제공합니다:
•
UI 폼 열기 및 닫기
•
UI 그룹 생성 및 관리
•
UI 폼 상태 확인
•
UI 폼 속성 설정
모든 UI 상호작용은 OpenUIForm(), CloseUIForm() 같은 메서드를 사용하는 이 컴포넌트를 통해 이루어져야 합니다.

UIForm

UIForm 클래스는 IUIForm 인터페이스의 Unity 구현으로, 단일 UI 창이나 패널을 나타냅니다. 각 UIForm은:
•
고유한 시리얼 ID를 가집니다
•
특정 UI 그룹에 속합니다
•
자신의 UIFormLogic 컴포넌트 참조를 가집니다
•
그룹 내에서 깊이 값(depth)을 가집니다
이 클래스는 프레임워크의 UI 관리 시스템과 Unity의 GameObject/컴포넌트 시스템 사이의 다리 역할을 합니다.

UIFormLogic

UIFormLogic은 모든 UI 전용 로직의 기본 클래스입니다. 게임 개발자는 이 클래스를 확장하여 각 UI 폼의 동작을 구현해야 합니다. 다음과 같은 수명주기 메서드를 제공합니다:
•
OnInit() : 폼이 초기화될 때 호출됨
•
OnOpen() : 폼이 열릴 때 호출됨
•
OnClose() : 폼이 닫힐 때 호출됨
•
OnRecycle() : 폼이 객체 풀로 반환될 때 호출됨
•
추가적으로 일시 정지, 커버 등의 수명주기 메서드 제공
사용자 정의 UI 로직 클래스는 UIFormLogic을 상속받아 구체적인 기능을 구현합니다.

UI 시스템 클래스 계층 구조

출처:
•
Scripts/Runtime/UI/UIComponent.cs 22-730
•
Scripts/Runtime/UI/UIForm.cs 17-304
•
Scripts/Runtime/UI/UIFormLogic.cs 15-207

UI 폼 수명주기

프레임워크의 UI 폼은 잘 정의된 수명주기를 따르며, 이를 통해 리소스와 상태를 적절하게 관리할 수 있습니다.
출처:
•
Scripts/Runtime/UI/UIFormLogic.cs 100-177
•
Scripts/Runtime/UI/UIForm.cs 106-268
각 상태는 UIFormLogic 내의 특정 메서드를 트리거합니다:
상태
메서드
설명
Initialized
OnInit
폼 인스턴스가 처음 생성될 때 한 번만 호출됨 (풀에서 다시 꺼낼 때는 호출되지 않음)
Opened
OnOpen
폼이 가시화될 때 호출됨
Closed
OnClose
폼이 닫힐 때 호출됨
Recycled
OnRecycle
폼이 객체 풀로 반환될 때 호출됨
Paused
OnPause
폼이 다른 폼에 의해 덮여 일시 정지될 때 호출됨
Resumed
OnResume
일시 정지 후 다시 표시 상태로 돌아올 때 호출됨
Covered
OnCover
다른 폼이 위에 나타날 때 호출됨
Revealed
OnReveal
덮고 있던 폼이 제거될 때 호출됨
Refocused
OnRefocus
폼이 다시 맨 앞으로 올 때 호출됨

UI 그룹과 깊이 관리

UI 시스템은 폼을 그룹으로 조직하며, 각 그룹은 고유한 깊이를 가집니다. 그룹 내에서 폼은 개별 깊이 값을 가져 표시 순서를 결정합니다.
출처:
•
Scripts/Runtime/UI/UIComponent.cs 73-245
•
Scripts/Runtime/UI/UIForm.cs 67-85
이 계층 구조는 다음과 같은 이점을 제공합니다:
•
높은 깊이 그룹의 폼은 항상 낮은 깊이 그룹의 폼 위에 표시됨
•
폼을 목적에 따라 조직 가능 (예: 메뉴, 대화창, HUD 요소)
•
그룹은 다른 동작을 가질 수 있음 (예: 독점 표시, 덮인 폼 일시 정지)

UI 시스템 사용하기

UI 그룹 설정하기

UI 그룹은 Unity 에디터에서 UIComponent에 정의하거나 런타임에 생성할 수 있습니다:
// 사용자 지정 깊이를 가진 새로운 UI 그룹 생성 uiComponent.AddUIGroup("Dialog", 10);
C#
복사

UI 폼 로직 생성하기

사용자 정의 UI 폼을 만들려면 UIFormLogic을 상속받아 필요한 수명주기 메서드를 구현합니다:
public class MainMenuUIForm : UIFormLogic { protected override void OnInit(object userData) { base.OnInit(userData); // UI 요소 초기화 및 이벤트 바인딩 } protected override void OnOpen(object userData) { base.OnOpen(userData); // UI 상태 설정 } protected override void OnClose(bool isShutdown, object userData) { // 폼 닫힐 때 정리 base.OnClose(isShutdown, userData); } }
C#
복사

UI 폼 열고 닫기

UI 폼은 UIComponent를 통해 열고 닫습니다:
// UI 폼 열기 int serialId = GameEntry.GetComponent<UIComponent>() .OpenUIForm("MainMenuForm", "Default"); // UI 폼 닫기 GameEntry.GetComponent<UIComponent>().CloseUIForm(serialId);
C#
복사

일시 정지 및 커버된 폼 다루기

폼을 열 때, 덮이는 폼을 일시 정지할지 지정할 수 있습니다:
// 아래 폼들을 일시 정지시키는 폼 열기 GameEntry.GetComponent<UIComponent>() .OpenUIForm("PauseMenuForm", "Dialog", true);
C#
복사

다른 시스템과의 통합

리소스 시스템

UI 폼은 리소스 시스템을 통해 에셋으로 로드됩니다.
출처: Scripts/Runtime/UI/UIComponent.cs 200-227

객체 풀 시스템

UI 시스템은 성능 향상을 위해 UI 폼 인스턴스에 객체 풀링을 사용합니다.
출처: Scripts/Runtime/UI/UIComponent.cs 209-214

구성 옵션

UIComponent는 Unity 에디터에서 설정할 수 있는 여러 구성 옵션을 제공합니다:
옵션
설명
Instance Auto Release Interval
풀링된 UI 폼을 해제할지 확인하는 주기
Instance Capacity
객체 풀에 유지할 최대 인스턴스 수
Instance Expire Time
사용되지 않는 인스턴스를 해제하기 전까지 유지할 시간
Instance Priority
UI 폼 객체 풀의 우선순위
UI Form Helper
UI 폼 인스턴스 생성 및 관리용 헬퍼
UI Group Helper
UI 그룹 생성 및 관리용 헬퍼
출처: Scripts/Runtime/UI/UIComponent.cs 46-74

이벤트 시스템

UI 시스템은 UI 폼 수명주기의 다양한 시점에서 이벤트를 발생시킵니다:
•
OpenUIFormSuccessEvent
•
OpenUIFormFailureEvent
•
OpenUIFormUpdateEvent
•
OpenUIFormDependencyAssetEvent
•
CloseUIFormCompleteEvent
이 이벤트들은 EventComponent를 통해 구독할 수 있습니다.
출처:
•
Scripts/Runtime/UI/UIComponent.cs 161-181
•
Scripts/Runtime/UI/UIComponent.cs 701-728

모범 사례

•
UI 폼을 그룹으로 조직:
◦
메뉴, 대화창, HUD 등 UI 유형별로 그룹을 나눔
◦
적절한 깊이를 할당하여 레이어링을 제어
•
객체 풀 활용:
◦
성능을 위해 적절한 풀링 설정 구성
◦
OnRecycle을 적절히 구현하여 리소스를 정리
•
적절한 수명주기 메서드 구현:
◦
OnOpen/OnClose를 사용하여 가시성 변화를 처리
◦
OnPause/OnResume으로 덮였을 때 업데이트 관리
◦
OnClose에서 이벤트 리스너를 정리
•
사용자 데이터 활용:
◦
폼을 열 때 관련 데이터를 전달
◦
사용 사례에 맞게 사용자 데이터를 구조화
•
UI 성능 모니터링:
◦
과도한 UI 폼 생성 여부 확인
◦
프레임워크의 프로파일링 도구를 사용하여 UI 관련 지표 추적