UI 제작 및 연동

유영준·2023년 1월 17일
0
post-thumbnail

저번에 만들었던 체력을 이제 UI를 통해 가시적으로 보이게 만들 것이다

UI 제작

우클릭 후 유저 인터페이스(UI) -> 위젯 블루프린트를 생성하자 이름은 UI_HPBar 로 해주었다

상단에 프로그래스 바를 끌어와 생성해주고, 우측 상단에 사이즈를 커스텀 -> 넓이 150, 높이 50 으로 설정해준다

이름은 PB_HPBar 로 지정했다

프로그래스 바를 우클릭 후 Vertical Box 로 Wrap 해주고, 위 아래에 각각 Spacer를 넣어준다

우측의 디테일창에서 각각의 비율을 40 : 20 : 40 으로 설정해준다

이후 프로그래스 바는 배경 초록색, progress 색은 빨강, 진행 방향은 우측에서 좌측으로 설정해준다


위젯 에셋 추가하기

위젯 에셋을 추가하기 위해서는 빌드 파일에서 UMG 를 추가해주어야 한다

프로젝트의 Source 폴더안에 있는 파일명.build.cs 파일에서 UMG 를 추가해준다

완료 되었다면, ABCharacter 클래스에 오브젝트를 생성해주자

ABCharacter.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "ArenaBattle.h"
#include "GameFramework/Character.h"
#include "ABCharacter.generated.h"

...

public:	

	...

	UPROPERTY(VIsibleAnywhere, Category = Stat)
	class UABCharacterStatComponent* CharacterStat;

	UPROPERTY(VisibleAnywhere, Category = Camera)
	USpringArmComponent* SpringArm;

	UPROPERTY(VisibleAnywhere, Category = Camera)
	UCameraComponent* Camera;

	UPROPERTY(VisibleAnywhere, Category = UI)
	class UWidgetComponent* HPBarWidget;
    
    ...
    

ABCharacter.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "ABCharacter.h"
#include "ABAnimInstance.h"
#include "DrawDebugHelpers.h"
#include "ABWeapon.h"
#include "ABCharacterStatComponent.h"
#include "Components/WidgetComponent.h"

// Sets default values
AABCharacter::AABCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	HPBarWidget   = CreateDefaultSubobject<UWidgetComponent>(TEXT("HPBARWIDGET"));

	HPBarWidget->SetupAttachment(GetMesh());

	HPBarWidget->SetRelativeLocation(FVector(0.0f, 0.0f, 180.0f));
	HPBarWidget->SetWidgetSpace(EWidgetSpace::Screen);


	static ConstructorHelpers::FClassFinder<UUserWidget> UI_HUD
	(TEXT("/Game/Book/UI/UI_HPBar.UI_HPBar_C"));

	if (UI_HUD.Succeeded())
	{
		HPBarWidget->SetWidgetClass(UI_HUD.Class);
		HPBarWidget->SetDrawSize(FVector2D(150.0f, 50.0f));
	}
    
    ...
    
}

이제 위젯 에셋을 데이터 값과 연동을 시키겠다

UserWidget 을 상속받는 클래스 ABCharacterWidget을 만들자

해당 클래스에 전달할 정보는 ABCharacterStatComponent 에서 가져올 것이다

델리게이트를 만들어 연동시키도록 하겠다

_ABCharacterStatComponent.h_

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "ArenaBattle.h"
#include "Components/ActorComponent.h"
#include "ABCharacterStatComponent.generated.h"

DECLARE_MULTICAST_DELEGATE(FOnHPIsZeroDelegate);
DECLARE_MULTICAST_DELEGATE(FOnHPChangedDelegate);

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class ARENABATTLE_API UABCharacterStatComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UABCharacterStatComponent();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;
	virtual void InitializeComponent() override;

public:	
	void SetNewLevel(int32 NewLevel);
	void SetDamage(float NewDamage);
	void SetHP(float NewHP);
	float GetAttack();
	float GetHPRatio();

	FOnHPIsZeroDelegate OnHPIsZero;
	FOnHPChangedDelegate OnHPChanged;
    
	...

}

ABCharacterStatComponent.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "ABCharacterStatComponent.h"
#include "ABGameInstance.h"

...

// Called when the game starts
void UABCharacterStatComponent::BeginPlay()
{
	Super::BeginPlay();
	SetNewLevel(Level);
}

...

void UABCharacterStatComponent::SetNewLevel(int32 NewLevel)
{
	auto ABGameInstance = Cast<UABGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));

	CurrentStatData = ABGameInstance->GetABCharacterData(NewLevel);
	if (nullptr != CurrentStatData)
	{
		Level = NewLevel;
		SetHP(CurrentStatData->MaxHP);
	}
}

void UABCharacterStatComponent::SetDamage(float NewDamage)
{
	SetHP(FMath::Clamp<float>(CurrentHP - NewDamage, 0.0f, CurrentStatData->MaxHP));
}

void UABCharacterStatComponent::SetHP(float NewHP)
{
	CurrentHP = NewHP;
	OnHPChanged.Broadcast();
	if (CurrentHP < KINDA_SMALL_NUMBER)
	{
		CurrentHP = 0.0f;
		OnHPIsZero.Broadcast();
	}
}

float UABCharacterStatComponent::GetAttack()
{
	return CurrentStatData->Attack;
}

float UABCharacterStatComponent::GetHPRatio()
{
	return (CurrentHP < KINDA_SMALL_NUMBER ? 0.0f : (CurrentHP / CurrentStatData->MaxHP));
}

이때 사용한 KINDA_SMALL_NUMBER 는 언리얼에서 제공하는 매크로 엡실론이다


이제 ABCharacterWidget 클래스를 정의해준다

ABCharacterWidget.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "ArenaBattle.h"
#include "Blueprint/UserWidget.h"
#include "ABCharacterWidget.generated.h"

/**
 * 
 */
UCLASS()
class ARENABATTLE_API UABCharacterWidget : public UUserWidget
{
	GENERATED_BODY()
	
	
public:
	void BindCharacterStat(class UABCharacterStatComponent* NewCharacterStat);

protected:
	virtual void NativeConstruct() override;
	void UpdateHPWidget();

private:
	UABCharacterStatComponent* CurrentCharacterStat;

	UPROPERTY()
	class UProgressBar* HPProgressBar;
};

ABCharacterWidget.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "ABCharacterWidget.h"
#include "ABCharacterStatComponent.h"
#include "Components/ProgressBar.h"

void UABCharacterWidget::BindCharacterStat(UABCharacterStatComponent* NewCharacterStat)
{
	CurrentCharacterStat = NewCharacterStat;
	NewCharacterStat->OnHPChanged.AddUObject(this, &UABCharacterWidget::UpdateHPWidget);
}

void UABCharacterWidget::NativeConstruct()
{
	Super::NativeConstruct();
	HPProgressBar = Cast<UProgressBar>(GetWidgetFromName(TEXT("PB_HPBar")));
	UpdateHPWidget();
}

void UABCharacterWidget::UpdateHPWidget()
{
	if (CurrentCharacterStat->IsValidLowLevel())
		if (nullptr != HPProgressBar)
			HPProgressBar->SetPercent(1- CurrentCharacterStat->GetHPRatio());

}

마지막으로 ABCharacter.cppBeginPlay에서 바인딩을 진행해주고

ABCharacter.cpp

void AABCharacter::BeginPlay()
{
	Super::BeginPlay();

	auto CharacterWidget = Cast<UABCharacterWidget>(HPBarWidget->GetUserWidgetObject());
	if (nullptr != CharacterWidget)
		CharacterWidget->BindCharacterStat(CharacterStat);
}

블루프린트의 Graph -> Class Setting 안에서 부모 클래스를 ABCharacterWidget으로 바꿔준다


완성된 화면 정상적으로 체력이 차감되는 것을 확인할 수 있다

profile
토비폭스가 되고픈 게임 개발자

0개의 댓글