Using C++ Timers in Unreal Engine

Timers are incredibly helpful for gameplay programming in Unreal Engine. The syntax is a little tricky if you’re not too familiar with C++, this blog post will cover all the important features and syntax on how to use C++ timers effectively in your game.

For a code example of timers check out my Survival Game (simple) or C++ Action Roguelike (delegate with parameters).

Set Timer

You set timers through the global timer manager which is available through GetWorld()->GetTimerManager() or the shorthand available in any Actor, GetWorldTimerManager() which returns the same timer manager. There are a couple of overloads (function variations) available to pass the function to execute, the interval between ticks (if looped) and flag to set looping, and the optional first delay. You can also set a timer to run the next frame by calling SetTimerForNextTick().

Code sample from SurvivalGame BombActor where we set a timer for a delayed explosion:

/* Activate the fuze to explode the bomb after several seconds */
void ASBombActor::OnUsed(APawn* InstigatorPawn)
{
  GetWorld()->GetTimerManager().SetTimer(
    FuzeTimerHandle, // handle to cancel timer at a later time
    this, // the owning object
    &ASBombActor::OnExplode, // function to call on elapsed
    MaxFuzeTime, // float delay until elapsed
    false); // looping?
}

The FTimerHandle is in the header file. Although you are not required to keep a reference to the handle, it’s recommended to put this in your header to properly clear or pause your timer instance.

/* Handle to manage the timer */
FTimerHandle FuzeTimerHandle;

The function OnExplode() has no parameters in this example. To pass along paremeters on timer elapsed, there is a different way to bind the function…

Using SetTimer() on a Function with Parameters

It’s possible to pass parameters into timer functions (delegates). The example is from Action Roguelike’s Projectile Attack. In this case, we bind the function by name instead.

FTimerHandle TimerHandle_AttackDelay;
FTimerDelegate Delegate; // Delegate to bind function with parameters
Delegate.BindUFunction(this, "AttackDelay_Elapsed", Character); // Character is the parameter we wish to pass with the function.

GetWorld()->GetTimerManager().SetTimer(TimerHandle_AttackDelay, Delegate, AttackAnimDelay, false);

To bind functions with parameters to a timer, it must be specified in the header with UFUNCTION(). You can remember this since the FTimerDelegate from the above example calls a function literally named .BindUFunction().

UFUNCTION()
void AttackDelay_Elapsed(ACharacter* InstigatorCharacter);

Clearing Timer(s)

When destroying or deactivating objects, make sure you clear any active timers. There are two ways of dealing with timer removal. You don’t need to do this for timers that have elapsed and aren’t looping.

void ASBombActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);

	// Ensure the fuze timer is cleared by using the timer handle
	GetWorld()->GetTimerManager().ClearTimer(FuzeTimerHandle);

	// Alternatively you can clear ALL timers that belong to this (Actor) instance.
	GetWorld()->GetTimerManager().ClearAllTimersForObject(this);
}

Advanced Considerations

There are a couple of things to consider that aren’t immediately obvious and/or are more relevant once you are optimizing your game.

High-Frequency Timers

It’s important to note that while you can run very high-frequency timers, these do not actually run asynchronously or on a higher ‘real’ framerate than your game. Let’s say your game runs on 60 FPS and you have a timer on 0.005 looping intervals. That’s about 200 times per second, internally it will still run approx. 200 times per second even at 60 frames per second! It’s important to realize though that this will execute multiple times in a loop, immediately after each other, and NOT spaced out smoothly every 0.005.

It will instead run about 3 times per frame in a burst, which is just a waste of execution and could be done 1 time per frame with a higher DeltaTime to compensate.

When does it Tick

The TickManager itself ticks between TickGroups. Specifically, between PostPhysics and PostUpdateWork. That’s relatively late in the GameThread frame. Keep this in mind for any potential dependencies as you might introduce a one-frame delay if implicit dependent objects have already ticked that frame.

Frame Stability

You should never use TickManager as an excuse to not optimize badly performing code or naturally expensive operations. Running them as timer functions on a lower frequency may cause an instable framerate rather than smooth performance which hinders player experience. There are a couple of alternatives such as time slicing (spreading the workload across multiple frames) or running the entire function asynchronous using Unreal’s Task System.

CPU Cache

If you are updating many of the same objects using the TickManager using individual ticks, you have no control over their execution order. Much like Unreal’s standard Ticking system. There are enormous performance benefits to maximizing the CPU’s instruction and data cache. While this is absolutely out of the scope of this article, the most relevant resource to learn more is UnrealFest’s Aggregating Ticks to Manage Scale in Sea of Thieves.

Closing

Timers are great for triggering delayed events and handling other time-based events that you may be inclined to put in your Tick() function instead.

Check out the API for FTimerManager API Documentation for more useful functions on timers. Including time remaining, finding the tick rate, active timers, pause/continue, etc.

References

16 Responses

  1. Thanks for the coupon on your course Tom, looks very useful. I have been coding my own UE4 C++ stuff for over a year but only noticed the timers today in the content examples. Going to do your course in case I’m missing out on any other useful tricks.

  2. Having some trouble. Have a Timer in my ACharacter class and it gives me the following error Images: https://ibb.co/gYycdy https://ibb.co/kYwkWJ I really don’t know what I should do. I’ve already included World.h and TimerManager.h, world is null but I don’t understand why. Please help me!

  3. Make sure that you are not using the GetWorldTimerManager().SetTimer(…) in the Constructor of the class you are trying to bind the function for. I found after a ton of time that it is not corrupted, and that rather you just need to move it into the BeginPlay() and it is ok. If you cannot open the Editor (via the launcher): 1. Move/comment the code out of your constructor 2. Recompile the project 3. Open via the editor.

    My best guess is that in the editor, it sees a null_ptr which is causing the crashes (from a decent amount of googling) when the GetWorldTimerManager().SetTimer(…) is in the constructor.

  4. For those of you saying the code crashes. Make sure the function you’re binding to is an UFUNCTION(), I’m not sure if it’s explicitly said in any tutorial or official documentation itself, but I found out it was crashing if it’s not and UFUNCTION().

    Best way to discover that kind of crashes is to launch the editor from VS (DebugGame Editor & Win64, compile and Play), so when editor crashes it throws a breakpoint in VS and you can sometimes figure out what’s going on based on call stack and some keywords.

    Hope it helps.

    Good tutorial btw, not much info about that topic.

  5. Exactly, which is what I did, just did a check for a nullpointer. But I’m curious as well as to what point in the init process, that a plugin, can start assuming that the system is indeed loaded loaded enough to make calls.

    I mean if GEngine is nullptr then we know nothing is going to be happy! lol

    • There is a problem in World.H, at GEngine->GetWorld()->GetTimerManager(), in that when it’s being called, when the editor is loading and the call is being made from a static library for blueprints, i.e. a plugin. Yeah, it blows up with a C5, null pointer in some fashion. Haven’t had the time to debug yet. Not really for sure why it’s upset, there is very little code in the function. It is just checking for GameInstance. This is on 4.10.4

    • That sounds highly unlikely mate. When in doubt, remove and recompile and see what happens. There really isn’t much going on in this small piece of code that can touch or corrupt your project, especially unlikely to make it impossible to recover.

      What else did you change? Can you recompile the project successfully and re-open the editor? More importantly, what line of code does the editor crash on specifically, with more information I can try to help.

      – Tom

      • This might sound crazy but it happened to me too. No matter what UE4 crashes on launch. To fix it I had to open Visual Studio, remove the setTimer code, and then rebuild the project to get UE4 to launch without crashing.

        • What engine version are you guys using? Without specific information like the exact error and line it’s failing on there isn’t much I can help you guys with.

          – Tom

Leave a comment on this post!