이 글은 Inflearn - Rookiss : 언리얼 엔진4 입문 강의를 듣고 정리한 글입니다.
목차.
개요
이 글에서는 언리얼 엔진을 사용하여 적을 공격하거나 플레이어가 피격당했을 때 체력(HP)이 감소하고,
이를 UI를 통해 현재 체력을 시각적으로 확인할 수 있는 기능을 구현하는 방법에 대해 다뤄보겠습니다.
Prograss Bar 추가
위젯 블루프린트를 하나 생성하고
팔레트에서 Prograss Bar를 검색해 체력바로 사용할 UI를 하나 추가해줍니다.
적절히 스케일을 조절하고 색은 빨간 계열로 맞춰주면 됩니다.
UI Widget 부모 클래스 변경
상단에 보면 Default로 부모 클래스가 User Widget으로 되어있습니다.
User Widget을 부모로 하는 C++ 클래스를 생성하고,
다시 UI 에디터 창으로 돌아와 그래프 -> 클래스 세팅을 눌러 부모 클래스를 방금 생성한 C++ 클래스로 변경해 줍니다.
C++ 클래스 코드 작성
적과 플레이어 모두 HP UI가 머리 위에 떠있어야 합니다.
모두 MyCharacter 클래스를 상속받고 있으니 MyCharacter 클래스에 HP UI를 생성하게 한다면 두 객체 모두 적용될 것입니다.
MyCharacter.h
....
public:
....
UPROPERTY(VisibleAnywhere)
class UWidgetComponent* HpBar;
MyCharacter.cpp
#include "Components/WidgetComponent.h"
#include "MyCharacterWidget.h"
AMyCharacter::AMyCharacter()
{
....
HpBar = CreateDefaultSubobject<UWidgetComponent>(TEXT("HPBAR"));
HpBar->SetupAttachment(GetMesh());
HpBar->SetRelativeLocation(FVector(0.f, 0.f, 200.0f));
HpBar->SetWidgetSpace(EWidgetSpace::Screen);
static ConstructorHelpers::FClassFinder<UUserWidget> UW(TEXT("WidgetBlueprint'/Game/UI/WBP_HpBar.WBP_HpBar_C'"));
if (UW.Succeeded())
{
HpBar->SetWidgetClass(UW.Class);
HpBar->SetDrawSize(FVector2D(200.f, 50.f));
}
}
void AMyCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
....
HpBar->InitWidget();
auto HpWidget = Cast<UMyCharacterWidget>(HpBar->GetUserWidgetObject());
if (HpWidget)
HpWidget->BindHp(Stat);
}
위 코드에서 EWidgetSpace::Screen은 절대 occludded로 항상 보이는 UI로 설정해 줍니다.
코드상 UI의 이름 끝에 _C를 추가했는데 규칙으로 인해 붙여주었습니다.
이제 HP를 감소시키고 현재 HP를 업데이트시켜줄 코드를 추가해야 합니다.
MyStatComponent.h
DECLARE_MULTICAST_DELEGATE(FOnHpChanged);
class TESTUNREALENGINE_API UMyStatComponent : public UActorComponent
{
public:
....
void SetHp(int32 NewHp);
int32 GetHp() { return Hp; }
int32 GetMaxHp() { return MaxHp; }
float GetHpRatio() { return Hp / (float)MaxHp; }
private:
....
UPROPERTY(EditAnywhere, Category = Stat, Meta = (AllowPrivateAccess = true))
int32 Hp;
UPROPERTY(EditAnywhere, Category = Stat, Meta = (AllowPrivateAccess = true))
int32 MaxHp;
....
public:
FOnHpChanged OnHpChanged;
}
델리게이트를 사용해 CallBack 방식을 사용했습니다.
MyStatComponent.cpp
void UMyStatComponent::SetHp(int32 NewHp)
{
Hp = NewHp;
if (Hp < 0)
Hp = 0;
OnHpChanged.Broadcast();
}
HP가 변하면 브로드 캐스트를 호출 -> 리스너(구독자) 패턴
MyCharacterWidget.h
UCLASS()
class TESTUNREALENGINE_API UMyCharacterWidget : public UUserWidget
{
GENERATED_BODY()
public:
void BindHp(class UMyStatComponent* StatComp);
void UpdateHp();
private:
TWeakObjectPtr<class UMyStatComponent>CurrentStatComp;
UPROPERTY(meta = (BindWidget))
class UProgressBar* PB_HpBar;
};
MyCharacterWidget.cpp
#include "MyStatComponent.h"
#include "Components/ProgressBar.h"
void UMyCharacterWidget::BindHp(UMyStatComponent* StatComp)
{
CurrentStatComp = StatComp;
StatComp->OnHpChanged.AddUObject(this, &UMyCharacterWidget::UpdateHp);
}
void UMyCharacterWidget::UpdateHp()
{
if(CurrentStatComp.IsValid())
PB_HpBar->SetPercent(CurrentStatComp->GetHpRatio());
}
결과
컴파일 후 게임을 실행하면 적의 HP가 잘 감소하는 것을 볼 수 있습니다.
지금까지 위젯 블루프린트에서 Prograss Bar를 추가하고
User Widget이었던 부모 클래스를 새로 생성한 C++ 클래스로 변경해 준 뒤,
코드로 기능을 구현했습니다.
위 코드에서 핵심 내용은 델리게이트를 활용해 HP가 감소되었을 때 브로드캐스트를 하는 것과,
BindHp를 통해서 플레이어의 Stat을 받아와 UI에 적용을 했고,
체력의 비율에 맞춰서 SetPercent를 통해 UI를 갱신해 주었습니다
'언리얼' 카테고리의 다른 글
[UE4] 언리얼 엔진 : 패키징 용량 최적화 (1) | 2023.09.09 |
---|---|
[UE4] 언리얼 엔진 : 레벨 전환시 화면 끊김 문제 해결하기 (0) | 2023.09.09 |
[UE4] 블루프린트를 활용한 레벨 간 이동 시스템 구현하기 (0) | 2023.09.09 |
[UE4] 언리얼 엔진 : 나이아가라 시스템으로 눈 파티클 생성 및 이동 구현 (0) | 2023.09.09 |
[UE4] 언리얼 엔진 : 익스포넨셜 하이트 포그(ExponentialHeightFog) 색 자동 설정 (0) | 2023.09.06 |