언리얼 C++ 프로그래밍

[언리얼 C++] 타이머 사용하기

언린이 2021. 6. 28. 21:03

언리얼 엔진에서는 게임플레이 타이머를 제공해줍니다. 게임플레이 타이머는 설정된 주기마다 동작을 수행하는 타이머 구조체입니다.

타이머를 통해 딜레이 이후 또는 일정 시간에 걸쳐 동작을 수행하도록 스케쥴을 잡을 수 있습니다. 그래서 타이머를 사용해서 게임에 여러가지 효과를 구현할 수 있습니다. 예를 들어, 플레이어가 사용한 버프가 지속시간 이후에 사라지는 것 등이 있을 것입니다.

 

 

1. 타이머 관리

타이머는 글로벌 타이머 매니저에서 관리합니다. 글로벌 타이머 매니저는 게임 인스턴스 오브젝트와 각 월드에 존재합니다. 타임 매니저와 함께 타이머를 셋업하는 데 사용되는 주 함수는 SetTimer와 SetTimerForNextTick 두 가지가 있는데,  둘다 다양한 파라미터로 셋업할 수 있도록 다수의 오버로드로 선언되어져 있습니다. 그래서 타이머는 표준 C++ 함수 포인터, TFunctionObjects, 델리게이트와 함께 사용할 수 있습니다.

 

 

2. 타이머 설정 및 해제

FTimerManager의 SetTimer 함수는 딜레이 후 함수나 델리게이트를 호출하는 타이머를 설정하며, 그 함수 호출을 무한 반복하도록 설정할 수 있습니다. 이 함수는 TimerHandle을 채우며, 이는 카운트다운 일시정지 및 재개, 남은 시간 확인 및 변경, 심지어 타이머 자체를 취소하는데도 쓸 수 있습니다.

 

그리고 타이머는 시간 간격이 아니라 다음 프레임에 실행되도록 설정할 수도 있습니다. SetTimerForNextTick을 호출하면 되는데, 이 함수는 타이머 핸들을 채우지 않는다는 점을 참고하시기 바랍니다.

 

타이머를 해제하려면, SetTimer 호출 도중 채워진 FTimerHandle을 ClearTimer라는 FTimerManager의 함수에 전달하면 됩니다. 이 시점에서 타이머 핸들은 유효하지 않은 상태가 되며, 새로운 타이머 관리를 위해 재사용할 수 있습니다. 기존 타이머 핸들로 SetTimer를 호출하면 그 타이머 핸들에 참조된 타이머를 해제하고 새로운 것으로 대체합니다.

 

void AMyActor::BeginPlay()
{
    Super::BeginPlay();
    
    // TestFunction 을 초당 1 회, 10 초간 호출합니다.
    GetWorldTimerManager().SetTimer(TestTimerHandle, this, &AMyActor::TestFunction, 1.0f, true, 10.0f);
}

void AMyActor::TestFunction()
{
    // 타이머 해제
    if (--CountDown <= 0)
    {
        GetWorldTimerManager().ClearTimer(TestTimerHandle);
    }
}

위의 코드처럼 SetTimer를 통해 주기마다 호출될 함수를 설정하고 해당 함수에서 특정 조건에 따라 타이머를 해제해줍니다. 참고로 해제된 타이머 핸들은 다른 타이머에서 재사용이 가능합니다.

 

또한, 타이머를 일시정지하고 재개할 수 있습니다.

void AMyActor::TimerPause()
{
    GetWorldTimerManager().PauseTimer(TestTimerHandle);
}

void AMyActor::TimerUnPause()
{
    GetWorldTimerManager().UnPauseTimer(TestTimerHandle);
}

 

FTimerManager의 함수 PauseTimer는 타이머 핸들을 사용하여 실행중인 타이머를 일시정지합니다. 그러면 그 타이머는 함수 호출 실행이 막히지만, 경과 및 남은 시간은 그대로 유지됩니다. UnPauseTimer는 일시정지된 타이머 실행을 재개합니다.

 

 

3. 타이머 정보

타이머 관리에 더해 타이머 매니저는 특정 타이머의 속도, 경과 시간, 남은 시간 등의 정보 획득을 위한 함수를 제공해줍니다.

 

// 지정된 타이머가 현재 활성화되어 있는지 체크
bool bTimerActive = GetWorldTimerManager().IsTimerActive(TestTimerHandle);

// 타이머의 현재 속도를 구함, 타이머 핸들이 유효하지 않은 경우 -1을 반환
float fTimerRate = GetWorldTimerManager().GetTimerRate(TestTimerHandle);

// 타이머의 경과 및 남은 시간을 반환함, 타이머 핸들이 유효하지 않은 경우 -1을 반환
float fTimerElapsed = GetWorldTimerManager().GetTimerElapsed(TestTimerHandle);

위의 코드처럼 FTimerManager의 다양한 함수를 사용하여 타이머의 정보를 획득할 수 있습니다.

 

 

이렇게 언리얼 엔진에서 제공하는 타이머 기능을 잘 활용한다면 여러가지 효과들을 손쉽게 구현할 수 있을 것입니다. 하지만 타이머는 조심히 사용해야 합니다. 현재 타이머 코드는 여러 스레드를 지원하지 않기 때문입니다. 게임 스레드 이외에서 타이머에 접근하려는 경우 어서트가 발생할 것입니다.