UI Architecture
1. 목적
Project Durian의 게임플레이 UI는 Unreal Engine MVVM으로 표시값을 갱신한다. UKzUISubsystem은 위젯의 생성·표시·재사용만 맡고, ViewModel 생성이나 MVVM Context 연결에는 관여하지 않는다.
게임 상태 갱신
AKzPlayerCharacter
-> 상태 변경 이벤트
UKzHudViewModel / UKzAbilityWheelViewModel
-> FieldNotify
WBP_Hud / WBP_AbilityWheel
위젯 수명 관리
Scene 또는 PlayerController
-> UKzUISubsystem::Open<TWidget>()
-> 위젯 표시 및 재사용
2. 책임
2.1 Model
AKzPlayerCharacter가 실제 능력 상태를 가진다.
- 현재 능력 등 게임 상태를 소유한다.
- 상태가 바뀌면 변경 이벤트를 방송한다.
- Widget, ViewModel, UI 표시 코드를 직접 참조하지 않는다.
2.2 ViewModel
모든 Durian ViewModel은 UKzViewModelBase를 상속한다. ViewModel은 Model의 상태를 UI가 바로 표시할 값으로 변환하고 FieldNotify로 알린다.
-
UKzHudViewModelAKzPlayerCharacter의 현재 능력을 구독한다.CurrentAbilityBrush를 갱신한다.- 능력 아이콘
FSlateBrush변환은 공용KzAbilityUtility를 사용한다.
-
UKzAbilityWheelViewModel- 휠의 열림 상태,
WheelVisibility,SelectedAbility,SelectionAngle을 관리한다. - PlayerController가 전달한 입력으로 선택 값을 변경하고, 확정 시 PlayerCharacter에 능력 변경을 요청한다.
- 휠의 열림 상태,
ViewModel은 TWeakObjectPtr<AKzPlayerCharacter>로 Character를 참조한다. Character를 소유하거나 Widget을 직접 조작하지 않는다.
2.3 View
WBP_Hud, WBP_AbilityWheel은 레이아웃·스타일·애니메이션·MVVM 바인딩을 가진 View다.
각 WBP는 Unreal의 Viewmodels 패널에서 사용할 ViewModel을 직접 선언한다.
| WBP | ViewModel | Creation Type |
|---|---|---|
WBP_Hud | UKzHudViewModel | Create Instance |
WBP_AbilityWheel | UKzAbilityWheelViewModel | Create Instance |
WBP가 생성될 때 Unreal MVVM이 이 ViewModel 인스턴스를 만들고 Context에 연결한다. Context 이름·ViewModel 클래스·SetViewModel 호출을 UI Manager에서 별도로 관리하지 않는다.
현재 주요 바인딩은 다음과 같다.
WBP_Hud
CurrentAbilityIcon.Brush <- UKzHudViewModel.CurrentAbilityBrush
WBP_AbilityWheel
Wheel Visibility <- UKzAbilityWheelViewModel.WheelVisibility
SelectOverlay 회전값 <- UKzAbilityWheelViewModel.SelectionAngle
표시값은 가능하면 FieldNotify가 붙은 프로퍼티를 직접 바인딩한다. ViewModel의 함수는 표시값을 계산해야 할 때만 사용한다.
UKzHudWidget, UKzAbilityWheelWidget은 WBP의 C++ 부모다.
- 각 클래스의
GetWidgetClass()가 대응하는 WBP 클래스를 반환한다. NativeConstruct()에서 Unreal MVVM이 만든 ViewModel을 찾아Initialize()를 호출한다.- UI 요소를
BindWidget으로 잡아 직접 갱신하지 않는다.
3. UI 관리자
UKzUISubsystem은 UGameInstanceSubsystem이다.
Open<TWidget>(): 위젯을 열거나 Pool의 인스턴스를 재사용한다.Get<TWidget>(): 열린 위젯을 가져온다.Register<TWidget>(): 위젯을 미리 만들어 Pool에 둔다.Close,Destroy: 표시 중인 위젯을 Pool로 옮기거나 완전히 제거한다.
UI Manager는 Widget 클래스와 인스턴스만 관리한다. 다음 책임은 없다.
- ViewModel Registry 또는 Factory
- ViewModel별 Widget 목록
- ViewModel Context 이름 관리
UMVVMView::SetViewModel()호출- Model 또는 PlayerCharacter 참조
4. 실행 흐름
4.1 HUD
Scene
-> UKzUISubsystem::Open<UKzHudWidget>()
-> WBP_Hud 생성
-> Unreal MVVM이 UKzHudViewModel 생성 및 연결
-> UKzHudWidget::NativeConstruct()
-> UKzHudViewModel::Initialize()
-> PlayerController의 Pawn 변경을 구독
-> PlayerCharacter의 능력 변경을 구독
-> CurrentAbilityBrush FieldNotify
-> WBP_Hud 이미지 갱신
Pawn이 아직 없을 때 ViewModel이 먼저 생성되어도, PlayerController의 Pawn 변경 이벤트를 받으면 Character 구독과 초기 표시값 갱신을 다시 수행한다.
4.2 Ability Wheel
AbilityWheel 입력 PressDown
-> UKzUISubsystem::Open<UKzAbilityWheelWidget>()
-> UKzAbilityWheelViewModel::OpenWheel()
-> WheelVisibility / SelectedAbility / SelectionAngle 갱신
-> WBP_AbilityWheel 바인딩 갱신
Look 입력
-> UKzAbilityWheelViewModel::AddSelectionDirection()
-> SelectedAbility / SelectionAngle 갱신
AbilityWheel 입력 PressUp
-> UKzAbilityWheelViewModel::ConfirmSelection()
-> PlayerCharacter의 능력 변경
-> UKzHudViewModel이 능력 변경 이벤트를 받아 HUD 갱신
PlayerController는 입력을 ViewModel 메서드에 전달할 수 있지만, Widget의 이미지·가시성·회전을 직접 바꾸지 않는다.
5. 위젯 추가 규칙
새 화면을 추가할 때에는 다음 두 곳만 정의한다.
- 대응하는 C++ Widget 부모에 WBP 클래스 경로를
GetWidgetClass()로 정의한다. - WBP의 Viewmodels 패널에서 ViewModel 클래스와 바인딩을 설정한다.
DA_UIRegistry, 문자열 Widget ID, UI Manager 내부 Widget-ViewModel Map은 사용하지 않는다. WBP가 자신이 사용할 ViewModel을 선언하고, UI Manager는 타입 기반 Open<TWidget>()만 제공한다.
6. Widget Pool과 표시 우선순위
UI Manager는 열린 위젯과 재사용 가능한 위젯을 분리해 관리한다.
Open
-> 이미 열려 있으면 반환
-> Pool에 있으면 재사용
-> 없으면 생성 후 표시
Close
-> 화면에서 숨김
-> Pool로 이동
Destroy
-> 관리 목록에서 제거
-> 참조가 없어지면 Unreal GC 대상
UKzBaseWidget의 UI 우선순위는 Root Layer의 표시 순서를 정한다. 이 우선순위는 ViewModel이나 게임 상태와 무관하다.
7. 현재 범위
현재 MVVM 적용 대상은 게임플레이 HUD와 Ability Wheel이다. 인벤토리, 메뉴, 조준·상호작용 피드백은 필요할 때 같은 규칙으로 추가한다.