[GAS/sec5] RPG Game UI
1. Game UI Architecture
UI가 데이터에 직접 접근하는 건 좋은 방식이 아니다.
데이터(Model)과 UI(View) 사이에 징검다리 역할을 해주는 클래스(Controller)를 따로 마련하자. Model에서 필요한 데이터를 검색해 View로 브로드캐스팅할 수 있다.
WidgetController의 역할
- 데이터 검색 후 뷰로 전달
- 뷰와 모델 사이의 중개자 역할
- 데이터 처리와 관련된 계산 및 알고리즘 수행
- UI 버튼을 통해 변경된 데이터를 모델에게 전달
View
⇢ Controller
⇢ Model
- 단방향 종속성 형태
- 모델은 어떤 컨트롤러나 위젯이 사용되는지 신경 X
- 컨트롤러는 어떤 위젯이 브로드캐스트를 수신하는지 알 필요 X
2. Widget Controller
2.1. User Widget
위젯이 컨트롤러의 브로드캐스트를 수신하기 위해 위젯 클래스에 컨트롤러에 대한 멤버 변수가 있어야 한다.
특정 위젯에 대한 위젯 컨트롤러가 설정되면 함수를 호출해 해당 컨트롤러에 대한 데이터를 받아오자. 컨트롤러에서 데이터를 받아와야 블루프린트에서 대응 이벤트를 만들 수 있다.
Widget 클래스에서 만들어야 할 것
- Widget Controller 멤버변수
- Widget Controller Set 함수
- Widget Controller와 함수간의 연결 (Setter)
위젯 컨트롤러는 위젯에 사용될 모델의 데이터를 가져오기 위해 TObjectPtr<클래스명>
형태의 멤버 변수를 선언한다(캐릭터 컨트롤러, 상태 등). 블루프린트에서 읽어올 수 있어야 하므로 UPROPERTY
를 추가하자.
위젯 컨트롤러 클래스에 구조체를 선언해 멤버 변수를 쉽게 초기화할 수 있다. 블루프린트에서 구조체를 사용하는 경우를 대비해 구조체 지정자 USTRUCT(BlueprintType)
를 추가한다.
2.2. Overlay Widget Controller
Health/Mana UI는 오버레이 위젯을 상속받은 BP를 통해 Viewport에 띄운다. 게임을 시작하면 위젯 컨트롤러에 속성값을 초기화시키고 위젯을 Viewport에 추가해야 한다.
위젯 컨트롤러의 초기화 및 적용은 HUD 클래스에 구현한다. Overlay Widget Controller를 싱글톤으로 관리하고 위젯의 속성값을 초기화하는 과정을 HUD 클래스에 작성한다. 오버레이 위젯을 초기화하는 함수를 만들어 오버레이 위젯이 필요한 속성값을 제공한다.
중단점을 사용해
InitOverlay
함수에서 입력 매개변수PC
가 어떤 값을 가지고 있는지 가지고 있는지 알 수 있다!
3. Broadcasting
Widget
⇢ Widget Controller
형태의 단방향 종속성을 유지하려면 컨트롤러가 초기 값을 브로드캐스트해야 한다. 컨트롤러가 초기값을 브로드캐스트하기 위해 BroadcastInitialValues
함수를 사용한다.
오버레이 위젯 컨트롤러에서 속성값을 브로드캐스트해야 하므로, UOverlayWidgetController
클래스에 델리게이트를 선언한다. 블루프린트에서도 접근이 가능하도록 멀티캐스트 델리게이트를 선언하자.
구현부에 BroadcastInitialValues
함수를 오버라이드해 초기값을 지정한다. 속성값은 AuraAttributeSet
를 캐스트해 Health와 MaxHealth를 가져올 수 있다.
cast
vsCastChecked
CastChecked
는 더 효율적인 캐스트 방식이나, 안전성이 떨어져 캐스트가 확실히 성공할 경우 사용한다.브로드캐스트로 초기값을 호출하면 NULL값이 나오지 않으므로
CastChecked
로 속성값을 호출할 수 있다.
1 2 3 // CastChecked ptrA = Cast< type >( ptrB ); check( ptrA != nullptr );
위젯 컨트롤러가 바인딩 된 이후에 브로드캐스트를 수행해야 하므로, HUD 클래스의 SetWidgetController
함수 이후에 브로드캐스트 함수를 호출하는 것이 적합하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void AAuraHUD::InitOverlay(APlayerController* PC, APlayerState* PS, UAbilitySystemComponent* ASC, UAttributeSet* AS)
{
// 위젯 및 위젯 컨트롤러 생성
// 위젯 컨트롤러 매개변수를 전달하는 GetOverlayWidgetController 함수 호출
...
// 위젯에 위젯 컨트롤러 설정
OverlayWidget->SetWidgetController(WidgetController);
// 위젯 컨트롤러가 바인딩 된 이후에 브로드캐스트를 수행해야 함!
WidgetController->BroadcastInitialValues();
Widget->AddToViewport();
}
BP_HUD나 HP/Mana progressbar에 위젯 컨트롤러를 바인딩하려면 원시cpp 클래스를 바인딩하기보단 BP로 확장한 후 바인딩하자!
위젯 컨트롤러가
BP_OverlayWidgetController
로 형변환되었다.
4. Listening & Callback
속성값이 변할 때마다 바인딩하는 함수를 만들 수 있다. BindCallbacksToDependencies
함수를 만들어 바인딩 함수를 작성하면 Health값이 변경될 때마다 브로드캐스트하고 적절한 함수가 호출된다.
GetGameplayAttributeValueChangeDelegate
함수를 통해 오브젝트를 바인딩하고 함수를 호출한다.
1
2
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(
AuraAttributeSet->GetHealthAttribute()).AddUObject(this, &UOverlayWidgetController::MaxHealthChanged);
AuraAttributeSet
클래스의Health
값이 변하면 호출AddUObject
: 콜백함수가 멤버 함수일 경우 사용(바인딩)- 바인딩할 오브젝트
- 호출할 함수
HUD 클래스의 위젯 컨트롤러 설정이 끝나고 컨트롤러가 반환되기 직전, 위젯 컨트롤러의 콜백 함수를 호출해 속성값이 변할 때마다 바인딩되도록 한다.
변경 사항이나 콜백을 바인딩하는 변경점이 있으면 해당 내용이 브로드캐스트된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
UOverlayWidgetController* AAuraHUD::GetOverlayWidgetController(const FWidgetControllerParams& WCParams)
{
if(OverlayWidgetController == nullptr)
{
/** 컨트롤러 설정 */
...
OverlayWidgetController->BindCallbacksToDependencies();
return OverlayWidgetController;
}
...
}
void AAuraHUD::InitOverlay(APlayerController* PC, APlayerState* PS, UAbilitySystemComponent* ASC, UAttributeSet* AS)
{
...
// 위젯에 위젯 컨트롤러 설정
OverlayWidget->SetWidgetController(WidgetController);
...
}
Leave a comment