언리얼 엔진 5/개발 일지

[UE5] 블루아카이브 TPS게임 개발일지 (47) - HP 자동회복 구현

ciel45 2024. 1. 20. 13:36

할게 많아서 최대한 간단하고 빠르게 자동회복을 구현해 볼 것이다.

 

현재 KannaCharacter에 달려있는 AttributeComponent에 다음과 같은 멤버를 추가하였다.

 

변수: IsRecovering, RecoverRate

함수: EnableHealthRegen(), DisableHealthRegen()

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

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "AttributeComponent.generated.h"

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class KANNATPS_API UAttributeComponent : public UActorComponent
{
	GENERATED_BODY()

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

	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	FORCEINLINE void EnableHealthRegen() { IsRecovering = true;};
	FORCEINLINE void DisableHealthRegen() { IsRecovering = false; };

/* 생략 */

	UPROPERTY(EditAnywhere, Category = "Actor Attributes")
	float RecoverRate;

	bool IsRecovering;
};

함수의 기능은 매우 간단하므로 설명을 생략하려고 한다.

 

IsRecovering은 회복을 할지 여부, RecoverRate는 회복량을 나타낸다.

 

회복을 시키는건 TickComponent함수에서 담당하도록 하였다.

컴포넌트 클래스의 TickComponent는 액터 클래스의 Tick과 같다.

 

 

void UAttributeComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
	if (IsRecovering)
	{
		CurrentHealth += DeltaTime * RecoverRate;
		if (CurrentHealth > MaxHealth)
		{
			CurrentHealth = MaxHealth;
			IsRecovering = false;
		}
	}
}

마찬가지로 굉장히 간단하다. 

RecoverRate에 DeltaTime을 곱해주었는데, 회복량이 프레임 당 시간에 구애받지 않도록 하기 위해서이다.

 

프레임이 낮은 저사양 컴퓨터에서는 HP 회복이 느리게 된다면 많이 억울할 것이다.

 

 

이제 또 다시 KannaCharacter의 TakeDamage로 들어가, 데미지를 받으면 자동회복 중이었을 시엔 자동회복을 멈추고, 3초 뒤에 자동회복이 시작되도록 할 것이다.

 

**** 2024.1.23 수정 ****

원래 타이머를 사용하는 방식이었는데, 버그가 있었다. 공격을 받고 무조건 3초 뒤에 재회복을 하기 때문에, 연속으로 계속하여 공격을 받아도 회복이 되었다. 따라서 피격 방향 표시기와 마찬가지로 FLatentActionInfo를 사용하기로 했다. 

 

1. KannaCharacter.h 헤더파일에 FLatentActionInfo 변수 추가

FLatentActionInfo HealthInfo;

2. BeginPlay에서 HealthInfo 초기화 (EnableHealthRegen 바인딩)

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

	/* 생략 */

	HealthInfo.CallbackTarget = this;
	HealthInfo.Linkage = 0;
	HealthInfo.ExecutionFunction = FName("EnableHealthRegen");
	HealthInfo.UUID = GetUniqueID();
}

3. TakeDamage에서 RetriggerableDelay로 HealthInfo 인보크 (EnableHealthRegen 실행)

float AKannaCharacter::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)													
{
	if (Attributes)
	{
		/* 생략 */

		// 데미지 받고 3초 뒤 자동회복 시작
		Attributes->DisableHealthRegen();

		UKismetSystemLibrary::RetriggerableDelay(GetWorld(), 3.f, HealthInfo);
	}

	/* 생략 */

	return DamageAmount;
}

 

TakeDamage 시 DisableHealthRegen으로 IsRecovering을 꺼준뒤, 3초 뒤에 EnableHealthRegen을 호출하여 자동회복이 시작되도록 하였다.

 

 

 

 

UE_LOG로 찍어본 결과 자동회복이 잘 되는 것을 볼 수 있었다.

 

다음에는 이 HP값을 이용해 화면 가장자리가 붉어지는 이펙트를 만들어 볼 것이다.