
UNSEEN 기간 동안 교육 강의를 보면서 개발을 진행하다 보니, 강의대로 UI 생성을 HUD 대신 PlayerController를 사용했었다.
UNSEEN 멘토링 어느날, 멘토님께서 왜 UI 생성을 PlayerController에서 해? 라고 물어보았고, 그 말에 나는 대답하지못했다. (다른 방법이 있는지 몰랐...)
개발이 완료된 지금 시점에서, PlayerController에 있는 모든 UI 로직을 정리하고, HUD로 옮겨본다.
AHUD 클래스는 언리얼 엔진의 Head-Up Display 시스템을 담당하는 기본 클래스입니다. HUD는 게임에서 플레이어에게 정보를 시각적으로 제공하는데 사용되며, 일반적으로 화면 상단에 게임 상태, 점수, HP등을 표현한다.
AHUD 클래스는 Owner - PlayerController 이다.

AHUD 내에서 PlayerState, Pawn 접근을 위해서는 아래 GetPlayerState,GetPawn 함수를 사용한다.
//PlayerState
AQLPlayerState* PS = PlayerOwner->GetPlayerState<AQLPlayerState>();
//Player Pawn
AQLCharacterPlayer *LocalPlayer = PlayerOwner->GetPawn<AQLCharacterPlayer>();
그리고, Pawn이나 PlayerState, PlayerController에서는 PlayerController - GetHUD 함수에서부터 클래스를 가져올 수 있다.
LocalHUD = Cast<AQLHUD>(PlayerController->GetHUD());
if (LocalHUD)
{
LocalHUD->CreateHUD();
}
이번 벨로그는 제 프로젝트에 AHUD 클래스를 적용하는 걸 목표로 합니다.

void AQLCharacterPlayer::OnRep_Controller()
{
Super::OnRep_Controller();
AQLPlayerController* PlayerController = Cast<AQLPlayerController>(GetController());
LocalHUD = Cast<AQLHUD>(PlayerController->GetHUD());
if (LocalHUD && LocalHUD->HUDNum() == 0)
//Respawn에 의해 여러번 호출되는 경향이 있음. 한번만 호출하도록 한다.
{
LocalHUD->CreateHUD();
}
}
CreateHUD 함수에서는 모든 UserWidget를 생성해서, 화면에 띄어준다.

위 클래스 모두 생성해서 HUDs 로 관리 (TMap 자료구조)

AHUD로 잘 연동된 모습을 볼 수 있다.
입력에 따른 HUD 띄우기 => PlayerController로 몇 가지 이동
상호작용 UI
- WB_Story
- WB_Menu
- WB_Inventory
- Win/Loose
AHUD 와 PlayerController 내에서 상호작용 UI를 모두 띄우기 때문에 Z-Order값을 조정해주었음.
Z-Order이란? Z-order는 주로 UI 요소와 2D 요소의 겹침 순서를 정의하는 데 사용됩니다. 초기값은 0으로, 값이 커지면 커질 수록 이전 숫자를 가진 이미지보다 위에 위치한다는 특징을 가지고 있습니다.
또한, HUD 클래스에 위치한 위젯은 모두 Visibility를 조절하였다.
Visibility를 조절하면서, 실제 상호작용 안 할 위젯은 조정할 수 있다.
Visible : 보이고 클릭 가능
Collapsed : 보이지 않고, layout에 공간을 차지 하지 않으며, 클릭 불가능
Hidden : 보이지 않고, layout에 공간을 차지하나 클릭은 불가능
Not Hit-Testable ( Self & All Children ) : 보이지만 클릭 불가능, 자식 + 나 모두 포함
Not Hit-Testable ( Self Only ) : 보이지만 나 자신만 클릭 불가능



//일부 발췌 중간자 역할을 담당
void AQLPlayerState::OnChangedStamina(const FOnAttributeChangeData& Data)
{
//OnChangedStamina 함수도, 델리게이트로 연결되어 있는 함수이다.
float CurrentStamina = Data.NewValue;
//클라인지 서버인지 구별할 필요없음, 어차피 Bound되어 있다면, 아래 구문을 수행하기 때문이다.
if (UpdateStaminaDelegate.IsBound())
{
UpdateStaminaDelegate.Execute(CurrentStamina, GetMaxStamina());
}
}
//값이 변경되어 전달옴, 그리고 UI를 변경
void AQLHUD::ChangedStaminaPercentage(float Stamina, float MaxStamina)
{
UQLUserWidget* Widget = Cast<UQLUserWidget>(HUDs[EHUDType::HUD]);
if (Widget)
{
Widget->ChangedStaminaPercentage(Stamina, MaxStamina);
}
}
AHUD로 옮기는 작업은 모두 끝났습니다! 다음에는 UI 최적화에 대해 공부하고, 현재 사용 중인 UI를 최적화 해보도록 하겠습니다!