
헤드 업 디스플레이의 생성 프로세스
헤드업디스플레이의 생성 과정
헤드 업 디스플레이(HUD)는 플레이어 컨트롤러에 의해 제작되고 관리되는 UI 객체
HUD의 구현은 위젯을 생성하고 이를 플레이어 뷰포트에 띄우는 과정으로 생성됨.
이렇게 만들어진 위젯은 자신을 소유한 플레이어 컨트롤러에 접근할 수 있음.


유저 인터페이스 - 위젯 블루프린트, UserWidget으로 WBP_ABHUD 위젯 생성

간단하게 HUD 위젯 제작

UserWidget을 상속받은 ABHUDWidget 클래스 생성

위젯의 부모 클래스 변경
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "ABPlayerController.generated.h"
/**
*
*/
UCLASS()
class ARENABATTLE_API AABPlayerController : public APlayerController
{
GENERATED_BODY()
public:
AABPlayerController();
protected:
virtual void BeginPlay() override;
// HUD Section
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = HUD)
TSubclassOf<class UABHUDWidget> ABHUDWidgetClass;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = HUD)
TObjectPtr<class UABHUDWidget> ABHUDWidget;
};
ABPlayerController.h
// Fill out your copyright notice in the Description page of Project Settings.
#include "Player/ABPlayerController.h"
#include "UI/ABHUDWidget.h"
AABPlayerController::AABPlayerController()
{
static ConstructorHelpers::FClassFinder<UABHUDWidget> ABHUDWidgetRef(TEXT("/Game/ArenaBattle/UI/WBP_ABHUD.WBP_ABHUD_C"));
if (ABHUDWidgetRef.Class)
{
ABHUDWidgetClass = ABHUDWidgetRef.Class;
}
}
void AABPlayerController::BeginPlay()
{
Super::BeginPlay();
FInputModeGameOnly GameOnlyInputMode;
SetInputMode(GameOnlyInputMode);
ABHUDWidget = CreateWidget<UABHUDWidget>(this, ABHUDWidgetClass);
if (ABHUDWidget)
{
ABHUDWidget->AddToViewport();
}
}
ABPlayerController.cpp


WBP_CharacterStat 위젯 생성

캐릭터 스탯 위젯 제작

HUD 위젯에 추가

초기화 프로세스의 정리
컴포넌트, 액터, UI 위젯의 초기화 과정

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameData/ABCharacterStat.h"
#include "ABCharacterStatComponent.generated.h"
DECLARE_MULTICAST_DELEGATE(FOnHpZeroDelegate);
DECLARE_MULTICAST_DELEGATE_OneParam(FOnHpChangedDelegate, float /*CurrentHp*/);
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnStatChangedDelegate, const FABCharacterStat& /*BaseStat*/, const FABCharacterStat& /*ModifierStat*/);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ARENABATTLE_API UABCharacterStatComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UABCharacterStatComponent();
protected:
virtual void InitializeComponent() override;
public:
FOnHpZeroDelegate OnHpZero;
FOnHpChangedDelegate OnHpChanged;
FOnStatChangedDelegate OnStatChanged;
void SetLevelStat(int32 InNewLevel);
FORCEINLINE float GetCurrentLevel() const { return CurrentLevel; }
FORCEINLINE void SetBaseStat(const FABCharacterStat& InBaseStat) { BaseStat = InBaseStat; OnStatChanged.Broadcast(GetBaseStat(), GetModifierStat()); }
FORCEINLINE void SetModifierStat(const FABCharacterStat& InModifierStat) { ModifierStat = InModifierStat; OnStatChanged.Broadcast(GetBaseStat(), GetModifierStat()); }
FORCEINLINE const FABCharacterStat& GetBaseStat() const { return BaseStat; }
FORCEINLINE const FABCharacterStat& GetModifierStat() const { return ModifierStat; }
FORCEINLINE FABCharacterStat GetTotalStat() const { return BaseStat + ModifierStat; }
FORCEINLINE float GetCurrentHp() const { return CurrentHp; }
FORCEINLINE float GetAttackRadius() const { return AttackRadius; }
float ApplyDamage(float InDamage);
protected:
void SetHp(float NewHp);
UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat)
float CurrentHp;
UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat)
float CurrentLevel;
UPROPERTY(VisibleInstanceOnly, Category = Stat, Meta = (AllowPrivateAccess = "true"))
float AttackRadius;
UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat, Meta = (AllowPrivateAccess = "true"))
FABCharacterStat BaseStat;
UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat, Meta = (AllowPrivateAccess = "true"))
FABCharacterStat ModifierStat;
};
ABCharacterStatComponent.h
// Fill out your copyright notice in the Description page of Project Settings.
#include "CharacterStat/ABCharacterStatComponent.h"
#include "GameData/ABGameSingleton.h"
// Sets default values for this component's properties
UABCharacterStatComponent::UABCharacterStatComponent()
{
CurrentLevel = 1;
AttackRadius = 50.0f;
bWantsInitializeComponent = true;
}
void UABCharacterStatComponent::InitializeComponent()
{
Super::InitializeComponent();
SetLevelStat(CurrentLevel);
SetHp(BaseStat.MaxHp);
}
void UABCharacterStatComponent::SetLevelStat(int32 InNewLevel)
{
CurrentLevel = FMath::Clamp(InNewLevel, 1, UABGameSingleton::Get().CharacterMaxLevel);
SetBaseStat(UABGameSingleton::Get().GetCharacterStat(CurrentLevel));
check(BaseStat.MaxHp > 0.0f);
}
float UABCharacterStatComponent::ApplyDamage(float InDamage)
{
const float PrevHp = CurrentHp;
const float ActualDamage = FMath::Clamp<float>(InDamage, 0, InDamage);
SetHp(PrevHp - ActualDamage);
if (CurrentHp <= KINDA_SMALL_NUMBER)
{
OnHpZero.Broadcast();
}
return ActualDamage;
}
void UABCharacterStatComponent::SetHp(float NewHp)
{
CurrentHp = FMath::Clamp<float>(NewHp, 0.0f, BaseStat.MaxHp);
OnHpChanged.Broadcast(CurrentHp);
}
ABCharacterStatComponent.cpp

UserWidget을 상속받은 ABCharacterStatWidget 클래스 생성

CharacterStat 위젯의 부모 클래스 변경

ABCharacterHUDInterface 인터페이스 생성
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ABCharacterHUDInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UABCharacterHUDInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class ARENABATTLE_API IABCharacterHUDInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual void SetupHUDWidget(class UABHUDWidget* InHUDWidget) = 0;
};
ABCharacterHUDInterface.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "GameData/ABCharacterStat.h"
#include "ABHUDWidget.generated.h"
/**
*
*/
UCLASS()
class ARENABATTLE_API UABHUDWidget : public UUserWidget
{
GENERATED_BODY()
public:
UABHUDWidget(const FObjectInitializer& ObjectInitializer);
public:
void UpdateStat(const FABCharacterStat& BaseStat, const FABCharacterStat& ModifierStat);
void UpdateHpBar(float NewCurrentHp);
protected:
virtual void NativeConstruct() override;
protected:
UPROPERTY()
TObjectPtr<class UABHpBarWidget> HpBar;
UPROPERTY()
TObjectPtr<class UABCharacterStatWidget> CharacterStat;
};
ABHUDWidget.h
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/ABHUDWidget.h"
#include "Interface/ABCharacterHUDInterface.h"
#include "ABHpBarWidget.h"
#include "ABCharacterStatWidget.h"
UABHUDWidget::UABHUDWidget(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
}
void UABHUDWidget::UpdateStat(const FABCharacterStat& BaseStat, const FABCharacterStat& ModifierStat)
{
FABCharacterStat TotalStat = BaseStat + ModifierStat;
HpBar->SetMaxHp(TotalStat.MaxHp);
CharacterStat->UpdateStat(BaseStat, ModifierStat);
}
void UABHUDWidget::UpdateHpBar(float NewCurrentHp)
{
HpBar->UpdateHpBar(NewCurrentHp);
}
void UABHUDWidget::NativeConstruct()
{
Super::NativeConstruct();
HpBar = Cast<UABHpBarWidget>(GetWidgetFromName(TEXT("WidgetHpBar")));
ensure(HpBar);
CharacterStat = Cast<UABCharacterStatWidget>(GetWidgetFromName(TEXT("WidgetCharacterStat")));
ensure(CharacterStat);
IABCharacterHUDInterface* HUDPawn = Cast<IABCharacterHUDInterface>(GetOwningPlayerPawn());
if (HUDPawn)
{
HUDPawn->SetupHUDWidget(this);
}
}
ABHUDWidget.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Character/ABCharacterBase.h"
#include "InputActionValue.h"
#include "Interface/ABCharacterHUDInterface.h"
#include "ABCharacterPlayer.generated.h"
/**
*
*/
UCLASS()
class ARENABATTLE_API AABCharacterPlayer : public AABCharacterBase, public IABCharacterHUDInterface
{
GENERATED_BODY()
public:
AABCharacterPlayer();
protected:
virtual void BeginPlay() override;
...
// UI Section
protected:
virtual void SetupHUDWidget(class UABHUDWidget* InHUDWidget) override;
};
ABCharacterPlayer.h
// Fill out your copyright notice in the Description page of Project Settings.
#include "Character/ABCharacterPlayer.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "InputMappingContext.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "ABCharacterControlData.h"
#include "UI/ABHUDWidget.h"
#include "CharacterStat/ABCharacterStatComponent.h"
...
void AABCharacterPlayer::SetupHUDWidget(UABHUDWidget* InHUDWidget)
{
if (InHUDWidget)
{
InHUDWidget->UpdateStat(Stat->GetBaseStat(), Stat->GetModifierStat());
InHUDWidget->UpdateHpBar(Stat->GetCurrentHp());
Stat->OnStatChanged.AddUObject(InHUDWidget, &UABHUDWidget::UpdateStat);
Stat->OnHpChanged.AddUObject(InHUDWidget, &UABHUDWidget::UpdateHpBar);
}
}
AABCharacterPlayer.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "GameData/ABCharacterStat.h"
#include "ABCharacterStatWidget.generated.h"
/**
*
*/
UCLASS()
class ARENABATTLE_API UABCharacterStatWidget : public UUserWidget
{
GENERATED_BODY()
protected:
virtual void NativeConstruct() override;
public:
void UpdateStat(const FABCharacterStat& BaseStat, const FABCharacterStat& ModifierStat);
private:
UPROPERTY()
TMap<FName, class UTextBlock*> BaseLookup;
UPROPERTY()
TMap<FName, class UTextBlock*> ModifierLookup;
};
ABCharacterStatWidget.h
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/ABCharacterStatWidget.h"
#include "Components/TextBlock.h"
void UABCharacterStatWidget::NativeConstruct()
{
Super::NativeConstruct();
for (TFieldIterator<FNumericProperty> PropIt(FABCharacterStat::StaticStruct()); PropIt; ++PropIt)
{
const FName PropKey(PropIt->GetName());
const FName TextBaseControlName = *FString::Printf(TEXT("Txt%sBase"), *PropIt->GetName());
const FName TextModifierControlName = *FString::Printf(TEXT("Txt%sModifier"), *PropIt->GetName());
UTextBlock* BaseTextBlock = Cast<UTextBlock>(GetWidgetFromName(TextBaseControlName));
if (BaseTextBlock)
{
BaseLookup.Add(PropKey, BaseTextBlock);
}
UTextBlock* ModifierTextBlock = Cast<UTextBlock>(GetWidgetFromName(TextModifierControlName));
if (ModifierTextBlock)
{
ModifierLookup.Add(PropKey, ModifierTextBlock);
}
}
}
void UABCharacterStatWidget::UpdateStat(const FABCharacterStat& BaseStat, const FABCharacterStat& ModifierStat)
{
for (TFieldIterator<FNumericProperty> PropIt(FABCharacterStat::StaticStruct()); PropIt; ++PropIt)
{
const FName PropKey(PropIt->GetName());
float BaseData = 0.0f;
PropIt->GetValue_InContainer((const void*)&BaseStat, &BaseData);
float ModifierData = 0.0f;
PropIt->GetValue_InContainer((const void*)&ModifierStat, &ModifierData);
UTextBlock** BaseTextBlockPtr = BaseLookup.Find(PropKey);
if (BaseTextBlockPtr)
{
(*BaseTextBlockPtr)->SetText(FText::FromString(FString::SanitizeFloat(BaseData)));
}
UTextBlock** ModifierTextBlockPtr = ModifierLookup.Find(PropKey);
if (ModifierTextBlockPtr)
{
(*ModifierTextBlockPtr)->SetText(FText::FromString(FString::SanitizeFloat(ModifierData)));
}
}
}
ABCharacterStatWidget.cpp

이득우의 언리얼 프로그래밍 Part2 - 언리얼 게임 프레임웍의 이해 강의 | 이득우 - 인프런
이득우 | 대기업 현업자들이 수강하는 언리얼 C++ 프로그래밍 전문 과정입니다. 언리얼 C++ 프로그래밍을 사용해 핵&슬래시 로그라이크 게임 예제를 처음부터 끝까지 체계적으로 제작하는 방법을
www.inflearn.com
'게임 개발 > 언리얼 5' 카테고리의 다른 글
언리얼5 - 리플렉션을 활용하는 언리얼 에디터 UI와 UI의 확장 (2) | 2024.12.19 |
---|---|
언리얼 5 - 게임 플로우 다듬기 (0) | 2024.12.19 |
언리얼 5 - 행동트리 모델의 구현 (0) | 2024.12.16 |
언리얼5 - 행동트리 모델의 이해 (1) | 2024.12.15 |
언리얼 5 - 게임 데이터 관리 (1) | 2024.12.12 |