본문 바로가기

게임프로그래밍/실습1

[언리얼 실습] 58. 패트롤 대기 시간 추가하기


목차

  1.  타이머 만들기
  2.  타이머에 맞춰서 에너미 패트롤 시키기

1. 타이머 만들기

 

타이머를 만들기 위해서는 FTimerHandle 구조체가 필요하다. 타이머핸들은 타이머를 관리하는 데 사용되는 구조체라고 한다.

 

class PRACTICE_API AEnemy : public ACharacter, public IHitInterface
{
// 생략

private:

FTimerHandle PatrolTimer; // 타이머 핸들
void PatrolTimerFinished(); // 콜백함수

}

 

타이머 핸들과 타이머가 다 되면 실행할 함수를 선언해주었다. 이제 함수를 정의해보자.

void AEnemy::PatrolTimerFinished()
{
	if (EnemyController && PatrolTarget)
	{
		FAIMoveRequest MoveRequest;
		MoveRequest.SetGoalActor(PatrolTarget);
		MoveRequest.SetAcceptanceRadius(15.f);
		EnemyController->MoveTo(MoveRequest);
	}
}

 

함수의 내용은 그저 타이머가 다 되면 이동시키는 역할을 한다.

이제 함수를 다시보면 안에 구문을 무려 3곳에서 사용한다는 것을 알 수 있고 앞으로 더 많은 곳에서 사용할 가능성이 있다. 

 

이 부분을 따로 함수로 다시 만들어주자.

 

void MoveToTarget(AActor* Target);
void AEnemy::MoveToTarget(AActor* Target)
{
	if (EnemyController == nullptr || Target == nullptr) return;
	FAIMoveRequest MoveRequest;
	MoveRequest.SetGoalActor(Target);
	MoveRequest.SetAcceptanceRadius(15.f);
	EnemyController->MoveTo(MoveRequest);
}

 

이제 이 구문을 쓰고 있던 부분을 함수로 고쳐주면 된다.

 

이렇게 함수를 리팩터링하고 이제 사용하도록 하자. 타이머를 사용하려고 한다.

 

BeginPlay()로 들어가보자.

 

void AEnemy::BeginPlay()
{
	Super::BeginPlay();
	if (HealthBarWidget)
	{
		HealthBarWidget->SetVisibility(false);
	}

	EnemyController = Cast<AAIController>(GetController());
	//MoveToTarget(PatrolTarget);

	GetWorldTimerManager().SetTimer(PatrolTimer, this, &AEnemy::PatrolTimerFinished, 5.f);
}

 

이렇게 하면 에너미가 게임 시작 후 5초 후에 움직인다.


2. 타이머에 맞춰서 에너미 패트롤 시키기

 

이제 에너미를 패트롤 시킬 차례이다. BeginPlay에서 주석으로 처리했던 부분은 다시 돌려놓고 밑에 타이머를 세팅했던 부분은 지우도록 하자.

 

void AEnemy::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (CombatTarget)
	{
		if (!InTargetRange(CombatTarget, CombatRadius))
		{
			CombatTarget = nullptr;
			if (HealthBarWidget)
			{
				HealthBarWidget->SetVisibility(false);
			}
		}
	}

	if (InTargetRange(PatrolTarget, PatrolRadius))
	{
		PatrolTarget = ChoosePatrolTarget();
		GetWorldTimerManager().SetTimer(PatrolTimer, this, &AEnemy::PatrolTimerFinished, 5.f);
	}
}

 

Tick 함수에서 에너미를 이동시키던 부분에서 콜백함수를 호출하면 된다. (에너미를 이동시키는 부분은 리팩터링을 통해 간소화 하였다.)

 

지금은 5초 마다 함수를 호출하지만 이 시간을 랜덤으로 지정하고 싶다. 랜덤한 시간값을 얻을 수 있게 헤더파일에서 최소 시간과 최대 시간을 지정하자.

 

UPROPERTY(EditAnywhere, Category = "AI Navigation")
float WaitMin = 5.f;
UPROPERTY(EditAnywhere, Category = "AI Navigation")
float WaitMax = 10.f;
void AEnemy::CheckPatrolTarget()
{
	if (InTargetRange(PatrolTarget, PatrolRadius))
	{
		PatrolTarget = ChoosePatrolTarget();
		const float WaitTime = FMath::RandRange(WaitMin, WaitMax);
		GetWorldTimerManager().SetTimer(PatrolTimer, this, &AEnemy::PatrolTimerFinished, WaitTime);
	}
}

 

랜덤 시간을 부르고 순찰하게 바꾸었다.

 

이렇게 해서 순찰 기능을 완성하였다. 다음에는 에너미가 캐릭터 발견시 캐릭터를 쫒아오도록 만들어 볼 것이다.