적 타워가 플레이어의 탱크를 향해 일정 시간마다 포탄을 발사하는 기능을 구현하려고 한다.
이를 위해 특정 콜백 함수를 일정 시간 후에 호출해 주는 타이머 기능을 알 필요가 있다.
타이머 관련 구조는 크게 세 가지로 구성되며 타이머매니저, 타이머핸들, 타이머가 그것이다.
타이머매니저는 전역적으로 모든 타이머 핸들러를 관리해준다.
글로벌 타이머 매니저는 Game Instance (게임 인스턴스) 오브젝트와 각 World (월드)에 존재한다. 타임 매니저와 함께 타이머를 셋업하는 데 사용되는 주 함수는 SetTimer
와 SetTimerForNextTick
두 가지가 있다. 타이머매니저가 타이머핸들에 타이머를 추가할 수 있다. 타이머를 추가할 때는 콜백 함수와 타이머핸들의 이름, 주기 등을 설정한다.
FTimerHandle FireRateTimerHandle;
UPROPERTY(EditAnywhere, Category = "Combat")
float FireRate = 2;
void CheckFireCondition();
먼저 콜백 함수를 등록할 FTimerHandle
을 생성하고, 발사 주기(FireRate)를 만들었다. 발사 주기는 개발 과정에서 쉽게 수정할 수 있도록 하기 위해 EditAnywhere 프로퍼티를 설정했다.
그리고 주기마다 실행할 콜백 함수인 CheckFireCondition
을 만들었다. 이름에서도 알 수 있듯이 타워와 탱크까지의 거리를 확인하고 거리 안에 들어왔을 때 Fire 함수를 작동하도록 구성할 예정이다.
GetWorldTimerManager()
를 통해 현재 월드의 타이머매니저를 가져올 수 있다. (이후 타이머매니저의 멤버함수를 사용하기 위해서는 #include "TimerManager.h"
필요)
SetTimer는 여러 가지 형태로 오버로드되어 있다.
그 중에 이것을 사용하려고 한다.
인자로는 각각 사용할 타이머핸들, 콜백 함수를 호출할 객체명, 콜백 함수(의 주소값), 반복 주기, 반복 여부를 설정했다.
GetWorldTimerManager().SetTimer(FireRateTimerHandle, this, &ATower::CheckFireCondition, FireRate, true);
반복 여부가 true
로 되어 있으면 일정 주기마다 게임이 종료될 때까지 계속 반복해서 콜백 함수를 호출하고, false
로 되어 있으면 설정한 InRate 이후에 최초 1회만 호출한다.
콜백 함수, 즉 일정 주기마다 수행할 작업은 다음과 같다.
탱크와 타워의 거리를 계산하는 InFireRange
함수를 만들었다.
bool ATower::InFireRange()
{
if (Tank != nullptr)
{
float Distance = FVector::Dist(GetActorLocation(), Tank->GetActorLocation());
return (Distance <= FireDistance);
}
return false;
}
이를 CheckFireCondition
함수 안에 구현한다.
void ATower::CheckFireCondition()
{
if (InFireRange())
{
Fire();
}
}
콜백 함수가 일정 주기마다 잘 실행되는지, 잘 실행된다면 Fire
함수까지 잘 실행되는지 판단하기 위해 Fire
함수에서 디버그 구체를 그려보도록 하고, 실행해서 결과를 살펴본다.
타워의 포신 부분이 잘 회전하고, 사정거리 안에 들어오니 2초 간격으로 구체를 생성, 즉 Fire 함수가 호출되고 있음을 알 수 있다.