이 글은 Inflearn - Rookiss : 언리얼 엔진4 입문 강의를 듣고 정리한 글입니다.

 

목차.

  1. 개요
  2. Prograss Bar 추가
  3. UI Widget 부모 클래스 변경
  4. C++ 클래스 코드 작성
  5. 결과

 

개요

 

이 글에서는 언리얼 엔진을 사용하여 적을 공격하거나 플레이어가 피격당했을 때 체력(HP)이 감소하고,

이를 UI를 통해 현재 체력을 시각적으로 확인할 수 있는 기능을 구현하는 방법에 대해 다뤄보겠습니다.

 

Prograss Bar 추가

 

위젯 블루프린트를 하나 생성하고
팔레트에서 Prograss Bar를 검색해 체력바로 사용할 UI를 하나 추가해줍니다.

적절히 스케일을 조절하고 색은 빨간 계열로 맞춰주면 됩니다.

 

Prograss-Bar-추가
Prograss Bar 추가

 

UI Widget 부모 클래스 변경

 

부모-클래스-User-Widget
부모 클래스 User 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가 잘 감소하는 것을 볼 수 있습니다.

 

HP-UI-감소
HP UI 감소

 

지금까지 위젯 블루프린트에서 Prograss Bar를 추가하고 
User Widget이었던 부모 클래스를 새로 생성한 C++ 클래스로 변경해 준 뒤,

코드로 기능을 구현했습니다.

위 코드에서 핵심 내용은 델리게이트를 활용해 HP가 감소되었을 때 브로드캐스트를 하는 것과,

BindHp를 통해서 플레이어의 Stat을 받아와 UI에 적용을 했고,

체력의 비율에 맞춰서 SetPercent를 통해 UI를 갱신해 주었습니다

 

+ Recent posts