본문 바로가기
언리얼_엔진_게임개발_공부/언리얼 C++

[언리얼/C++] 타이머 사용하기 / FTimerManager, FTimerHandle, SetTimer()

by jaboy 2025. 1. 24.

참고: https://dev.epicgames.com/documentation/en-us/unreal-engine/gameplay-timers-in-unreal-engine

참고: https://milleatelier.tistory.com/104

 

[Unreal Engine] SetTimer() : C++ & Blueprint

게임을 만들다보면, 시간에 관계되는 이벤트를 만들어야 되는 상황이 많이 발생합니다. 개발에 정답은 없는만큼, 이러한 이벤트를 구현하는 방법 또한 여러가지가 될 수 있습니다만, 언리얼 엔

milleatelier.tistory.com

 

 

1. 현재 월드의 타이머 매니저

 

 

언리얼 엔진의 UWorld 에는 타이머를 관리하는 FTimerManager 타입의 멤버 변수가 있다.

그리고 이 TimerManager 의 SetTimer 함수를 통해 Duration, Loop 여부, 호출할 함수 등을 지정한다.

즉, 타이머 관련 로직을 구현할 때 아래와 같이 타이머 매니저를 가져와 SetTimer를 호출한다.

GetWorld()->GetTimerManager().SetTimer(...아래 이어지는 설명 참고...);

// 또는 AActor 멤버함수인 GetWorldTimerManager() 사용
GetWorldTimerManager().SetTimer(...);

 

AActor 내에 GetWorldTimerManager 함수의 정의를 살펴보면 똑같은 호출을 하고 있음을 알 수 있었다.
UWorld 의 GetTimerManager는 현재 게임 인스턴스의 타이머 매니저를 참조로 반환한다.

 

2. SetTimer()

FTimerManager 의 SetTimer 함수를 엔진에서 어떻게 정의했는지 살펴보았다.

/**
 * Sets a timer to call the given native function at a set interval.  If a timer is already set
 * for this handle, it will replace the current timer.
 *
 * @param InOutHandle			If the passed-in handle refers to an existing timer, it will be cleared before the new timer is added. A new handle to the new timer is returned in either case.
 * @param InObj				Object to call the timer function on.
 * @param InTimerMethod			Method to call when timer fires.
 * @param InRate			The amount of time (in seconds) between set and firing.  If <= 0.f, clears existing timers.
 * @param InbLoop			true to keep firing at Rate intervals, false to fire only once.
 * @param InFirstDelay			The time (in seconds) for the first iteration of a looping timer. If < 0.f InRate will be used.
 */
template< class UserClass >
FORCEINLINE void SetTimer(FTimerHandle& InOutHandle, UserClass* InObj, typename FTimerDelegate::TMethodPtr< UserClass > InTimerMethod, float InRate, bool InbLoop = false, float InFirstDelay = -1.f)
{
	InternalSetTimer(InOutHandle, FTimerUnifiedDelegate( FTimerDelegate::CreateUObject(InObj, InTimerMethod) ), InRate, InbLoop, InFirstDelay);
}
template< class UserClass >
FORCEINLINE void SetTimer(FTimerHandle& InOutHandle, UserClass* InObj, typename FTimerDelegate::TConstMethodPtr< UserClass > InTimerMethod, float InRate, bool InbLoop = false, float InFirstDelay = -1.f)
{
	InternalSetTimer(InOutHandle, FTimerUnifiedDelegate( FTimerDelegate::CreateUObject(InObj, InTimerMethod) ), InRate, InbLoop, InFirstDelay);
}

/** Version that takes any generic delegate. */
FORCEINLINE void SetTimer(FTimerHandle& InOutHandle, FTimerDelegate const& InDelegate, float InRate, bool InbLoop, float InFirstDelay = -1.f)
{
	InternalSetTimer(InOutHandle, FTimerUnifiedDelegate(InDelegate), InRate, InbLoop, InFirstDelay);
}
/** Version that takes a dynamic delegate (e.g. for UFunctions). */
FORCEINLINE void SetTimer(FTimerHandle& InOutHandle, FTimerDynamicDelegate const& InDynDelegate, float InRate, bool InbLoop, float InFirstDelay = -1.f)
{
	InternalSetTimer(InOutHandle, FTimerUnifiedDelegate(InDynDelegate), InRate, InbLoop, InFirstDelay);
}
/*** Version that doesn't take a delegate */
FORCEINLINE void SetTimer(FTimerHandle& InOutHandle, float InRate, bool InbLoop, float InFirstDelay = -1.f)
{
	InternalSetTimer(InOutHandle, FTimerUnifiedDelegate(), InRate, InbLoop, InFirstDelay);
}
/** Version that takes a TFunction */
FORCEINLINE void SetTimer(FTimerHandle& InOutHandle, TFunction<void(void)>&& Callback, float InRate, bool InbLoop, float InFirstDelay = -1.f )
{
	InternalSetTimer(InOutHandle, FTimerUnifiedDelegate(MoveTemp(Callback)), InRate, InbLoop, InFirstDelay);
}

 

매개변수로 다음과 같은 것을 넘겨받고 있음을 알 수 있다. (함수 매개변수 InTimerMethod 는 설명이 길어 마지막에 넣었다.)

 

1. FTimerHandle& InOutHandle : SetTimer 함수로 지정된 현재 타이머의 고유한 핸들 (FTimerHandle) 이다.

다른 SetTimer 호출에서 똑같은 함수 델리게이트를 등록하여도 FTimerHandle 을 달리함으로써 별개로 실행될 수 있게 하므로 필요하다.

만일 SetTimer 호출 시 인자로 전달하는 타이머핸들이 이미 다른 SetTimer 에서 지정되었던 경우, 해당 타이머를 제거하고 현재 타이머를 새로 등록한다.

 

2. UserClass* InObj : 타이머의 함수가 호출될 객체

 

3. float InRate : 타이머 시작부터 함수 호출 (firing) 까지 시간

 

4. bool InbLoop : 반복 여부

 

5. float InFirstDelay : looping 타이머의 경우, 첫 실행까지의 딜레이 별도 설정 가능

 

3. InTimerMethod / InDelegate / InDynDelegate / Callback : 타이머가 호출할 함수

위에 보다시피 SetTimer 는 오버로딩을 통해 호출할 함수를 여러가지 형태로 넘길 수 있도록 하고 있다.

가장 아래에서 두 번째 버전?은 함수를 입력받지 않는 버전이다.

함수를 어떤 형태로 넘길 수 있는지 위에서부터 살펴보자.

 

1) FTimerDelegate::TMethodPtr / TConstMethodPtr <UserClass> InTimerMethod

>> 타입이름에서 알 수 있듯이 메서드 포인터를 받고 있다. 따라서 아래와 같이 호출할 수 있을 것이다.

// 타이머 핸들 선언
FTimerHandle ThisHandle;

/////////////////////////////////

GetWorld()->GetTimerManager().SetTimer(
	ThisHandle, // InOutHandle : 멤버 변수
    this, // InObj : 현재 객체
    &ClassName::FunctionName, // InTimerMethod : 클래스 메서드 주소값
    1.0f, // InRate : 실행 주기
    true, // InbLoop : 반복 여부
    3.0f // InFirstDelay : 최초 실행까지 딜레이
);

 

2)  FTimerDelegate InDelegate

델리게이트에 대해...서는 다른 게시글로 정리해보아야겠다.

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/delegates-and-lamba-functions-in-unreal-engine

--> 일단 '객체에 클래스 멤버 함수를 참조/실행하는 자료형' 으로 알고 넘어가고. IsBound 체크가 필수인 것도 주의하고.

 

아래와 같이 FTimerDelegate 멤버 변수를 만들어 함수를 바인드 해준 후 인자로 넘길 수 있다.

// 타이머 핸들 선언
FTimerHandle ThisHandle;
// 타이머 델리게이트 선언
FTimerDelegate ThisDelegate;

/////////////////////////////////

/////// 델리게이트에 바인드 ////////
// 1. 람다 표현식으로 함수 바인드
ThisDelegate.BindLambda([]() {
	// ...
});

// 2. UObject 멤버 메서드 바인드 - weak reference
ThisDelegate.BindUObject(this, &ClassName::FunctionName);

// 3. 그 외 BindRaw (raw pointer), BindSP (shared pointer), BindStatic (raw pointer global function) 등 문서 참조


/////// SetTimer 에서 바인드된 델리게이트 호출 ////////
GetWorld()->GetTimerManager().SetTimer(
	ThisHandle, // InOutHandle : 멤버 변수
    this, // InObj : 현재 객체
    ThisDelegate, // InDelegate : 델리게이트
    1.0f, // InRate : 실행 주기
    true, // InbLoop : 반복 여부
    3.0f // InFirstDelay : 최초 실행까지 딜레이
);

//////// 델리게이트의 CreateLambda 를 활용할 수도 있다 ////////
GetWorld()->GetTimerManager().SetTimer(
	ThisHandle, // InOutHandle : 멤버 변수
    this, // InObj : 현재 객체
    FTimerDelegate::CreateLambda(
    [] () {
    	// ....
    }),
    1.0f, // InRate : 실행 주기
    true, // InbLoop : 반복 여부
    3.0f // InFirstDelay : 최초 실행까지 딜레이
);

 

 

3) FTimerDynamicDelegate InDynDelegate

위와 비슷한데, 다이내믹 델리게이트는 serialization 이 가능, 일반 델리게이트보다 느림

다이내믹 델리게이트가 무엇인지는 여기에서...

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/dynamic-delegates-in-unreal-engine

https://darkcatgame.tistory.com/66

 

UE4 C++ Delegate 정리 & 샘플 프로젝트

개인적으로 UE4 C++에서 Delegate를 사용할 때 처음에 굉장히 에러를 많이 겪었습니다, 그래서 이번 포스팅은 UE4 C++에서 Delegate를 사용하는 방법에 대해 정리하고 샘플프로젝트도 만들었습니다. https

darkcatgame.tistory.com

 

4) TFunction<void(void)>&& Callback

TFunction 은 그냥 언리얼 엔진의 람다 표현식이라고 보면 된다고 한다.

https://forums.unrealengine.com/t/can-someone-give-me-code-snippet-of-how-to-use-tfunction/138531

 

Can someone give me code snippet of how to use TFunction?

FWebBrowserWindow::GetSource(TFunction<void(const FString&)> Callback) const; I need to use GetSource to get html content, does anyone know how to input a correct TFunction ? Thanks. 🙁

forums.unrealengine.com

https://forums.unrealengine.com/t/tfunction-as-parameter-syntax-problem-solved/654329

 

TFunction as parameter syntax problem [SOLVED]

Hi all, How does the syntax work for providing a function argument of the type TFunction given the following situation: // in file 1 void UMyObject::StaticFunction(TFunction<void(AActor*)> functionAsParam) { functionAsParam(GetSomeActor()); } // in file 2

forums.unrealengine.com

 

GetWorld()->GetTimerManager().SetTimer(
	ThisHandle, // InOutHandle : 멤버 변수
    this, // InObj : 현재 객체
    []() {
    
    }, // Callback : TFunction
    1.0f, // InRate : 실행 주기
    true, // InbLoop : 반복 여부
    3.0f // InFirstDelay : 최초 실행까지 딜레이
);


/// 또는 아래와 같이 람다 표현식을 변수화하고 인자로
TFunction<Type(Type)> FunctionName = []() {
	//...
};

// 또는 아래와 같이 멤버 메서드를 TFunction 변수화하여 인자로
TFunction(Type(Type)> FunctionName = &ClassMethodName;

 

한줄평

언리얼 엔진의 함수 델리게이트에 대해 더 알아보아야겠다...ㅋ