Set Timer by Event / Clear Timer by Handle¶
At a glance
Lives in: Blueprint API / Utilities / Time -
Set Timer by Event returns: a Timer Handle struct -
Clear Timer by Handle returns: nothing -
Can fail by: never firing, being cleared/replaced, using Time <= 0,
losing the handle, or the bound object going away -
Official docs: Gameplay Timers,
Set Timer by Event
The one-minute version¶
Set Timer by Eventasks the world's timer manager to call your event later, either once or repeatedly.- The return value is a Timer Handle. Store it if you need to clear, pause, resume, or replace that specific timer.
- A timer is not a thread. The callback runs on a later game frame on the game thread.
- Setting a timer with an existing handle replaces the timer that handle was managing.
- A
Timevalue less than or equal to0clears the timer instead of starting a useful countdown. - Use timers for cooldowns, poison ticks, delayed cleanup, and periodic checks; use Tick, Timelines, or movement systems for smooth per-frame motion.
What Set Timer by Event actually does¶
The node binds an event/delegate to the world's timer manager. The manager tracks elapsed game time and calls the delegate when the timer expires.
pseudocode of the engine behavior - not engine source
function SetTimerByEvent(Event, Time, Looping, ExistingHandle):
if Time <= 0:
clear timer referenced by ExistingHandle
return invalid-or-cleared handle
if ExistingHandle already references a timer:
clear that old timer
create timer:
delegate = Event
rate = Time
looping = Looping
initial delay = optional start delay
return handle for that timer
The handle is not the event and not the timer's work. It is the ID card you use when you want to talk to the timer manager about that scheduled callback.
The handle is the cleanup tool¶
Store the handle in a variable when the timer has gameplay lifetime:
BeginOverlap
-> Set Timer by Event
Event = ApplyPoisonTick
Time = 1.0
Looping = true
-> Set PoisonTimerHandle
EndOverlap
-> Clear and Invalidate Timer by Handle
Handle = PoisonTimerHandle
If you do not store the handle, the timer can still fire, but your graph has no specific handle to clear later. That is fine for one-off "call this once after 0.2 seconds" work. It is a problem for loops, buffs, cooldowns, and anything that must stop when state changes.
Clear Timer by Handle stops the timer referenced by that handle. Many graphs
use Clear and Invalidate Timer by Handle because it also marks the stored
handle as no longer pointing at an active timer.
Looping, frame timing, and catch-up¶
A looping timer with Time = 1.0 means "call this roughly once per second
while the world is ticking." It does not mean exact real-time scheduling
outside the frame loop.
At 60 frames per second, the timer manager can only notice expiration when a
frame reaches it. If a frame takes longer than expected, a looping timer may be
late. UE5's Max Once Per Frame input exists for looping timers that might
otherwise need to catch up more than once in one frame.
Use the timer for the gameplay cadence:
Poison damage every 1.0 seconds
Weapon cooldown after 0.35 seconds
Scan for nearby interactables every 0.25 seconds
Do not use a timer to move a platform smoothly. Use a Timeline or Tick with Delta Seconds so the value can change every visible frame.
When it fails (and what failure does)¶
Timers fail silently. If the manager never calls your event, no Failed pin runs.
Common causes:
Time <= 0. The set call clears the timer instead of scheduling a callback.- You reused the same handle. The old timer was replaced by the new one. This is useful for cooldown resets and a bug when two systems share one handle variable by accident.
- You cleared it. EndOverlap, EndPlay, death, or a reset path may have stopped the timer before it fired.
- The bound object was destroyed. A timer bound to an object should not call into a destroyed object.
- The world is paused or not ticking the way you expect. Timer behavior is tied to world time and frame processing.
- The event target is wrong. You set a timer on one actor instance and watched another.
- The looping timer is slower than Tick. That is the point. It only fires at its interval, not every frame.
Failure does not log, retry, or call a fallback event by default. Print when you set and clear the timer, and print inside the callback while debugging.
What timers do not do¶
- They do not create a background thread.
- They do not run while the owning world/object cannot validly receive the callback.
- They do not store gameplay state beyond the scheduled callback.
- They do not replicate. A server timer and a client timer are separate timers in separate worlds.
- They do not replace Tick for smooth motion or animation.
- They do not survive normal
Open Leveltravel unless the object/world that owns the timer survives and sets it again.
The pattern everyone actually uses¶
For damage over time:
BeginOverlap poison volume
-> Add actor to PoisonedActors set
-> if PoisonTimerHandle is not active:
Set Timer by Event ApplyPoisonTick
Time = 1.0
Looping = true
Store handle
ApplyPoisonTick
-> For Each PoisonedActors
-> Is Valid
-> Apply Damage
-> Remove invalid actors from set
EndOverlap
-> Remove actor from PoisonedActors set
-> if PoisonedActors length == 0:
Clear and Invalidate Timer by Handle
For a weapon cooldown:
FireWeapon
-> Branch bCanFire
-> Set bCanFire false
-> spawn projectile / play effects
-> Set Timer by Event ResetCanFire
Time = FireCooldown
Looping = false
-> Store FireCooldownHandle
ResetCanFire
-> Set bCanFire true
The C++ twin, for the curious (our own example code):
void APoisonVolume::BeginPlay()
{
Super::BeginPlay();
GetWorldTimerManager().SetTimer(
PoisonTimerHandle,
this,
&APoisonVolume::ApplyPoisonTick,
1.0f,
true);
}
void APoisonVolume::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
GetWorldTimerManager().ClearTimer(PoisonTimerHandle);
Super::EndPlay(EndPlayReason);
}
Lookalikes - which one do I want?¶
| Node/tool | Use when | Watch out |
|---|---|---|
| Set Timer by Event | You want a custom event called later or repeatedly. | Store the handle when the timer must stop later. |
| Set Timer by Function Name | You have a named function path and accept string-name coupling. | Renames are easier to break; event handles are clearer in Blueprints. |
| Clear Timer by Handle | You want to stop a stored timer. | The handle must be the one returned when setting that timer. |
| Delay | You need one simple latent pause in one execution path. | No reusable handle; repeated calls while pending are ignored. |
| Event Tick | Work must run every frame. | Do not poll slow checks every frame if a timer interval is enough. |
| Timeline | You need a value changing smoothly over time. | Timers are poor animation curves. |
Rule of thumb: timer for named delayed/repeating callbacks, Delay for a tiny one-off wait, Timeline for curved motion, Tick for every-frame work.
Going deeper¶
- The frame: Tick, timers, and timelines - how timers fit into the frame loop.
- Delay, DoOnce, Gate, Sequence, and latent flow - when a latent node is simpler than a stored timer.
- Arrays, Sets, Maps, and ForEach - using a set for current timer targets.
- Destroy Actor / Set Life Span - object lifetime and delayed cleanup.
- Status effects and damage-over-time with timers
- a receiver-side pattern for poison, burn, slow, stun, timed buffs, and their timer cleanup.
- Official docs: Gameplay Timers, Set Timer by Event, and Delay.
- Engine source (requires engine access - we do not reproduce it here):
Blueprint wrappers such as
UKismetSystemLibrary::K2_SetTimerDelegateand timer clear helpers inEngine/Source/Runtime/Engine/Private/KismetSystemLibrary.cpp; timer scheduling and ticking throughFTimerManager::SetTimer,FTimerManager::ClearTimer, andFTimerManager::TickinEngine/Source/Runtime/Engine/Private/TimerManager.cpp.