"I want this to run every frame, so I'll just wire it to Event Tick." That works. But keep that habit, line up 100 enemies, and your frame rate quietly starts falling apart.
The danger of Event Tick is that each individual call is cheap, but the cost multiplies with the number of Actors. In this article we cover Tick-less design: switching from "always watching" to "only acting when something happens," along with three alternatives. In the hands-on section we rebuild a Tick-heavy guard AI into an AI that can sleep completely.
What You'll Learn
- Tick cost explodes at 60 times per second times the number of Actors
- The motto for going Tick-less: stop watching, get told instead (event-driven design)
- Three alternatives: Timer, Event Dispatcher, and Collision Events
- Tick Interval and on/off switching for when you truly need Tick
- Hands-on: rebuilding a guard AI so it can sleep completely
The Cost and Problems of Event Tick
Event Tick runs every frame for as long as the Actor is active. At 60 FPS, that's 60 times per second. So far so familiar. The problem is what happens when you multiply.

If 100 enemies each run a distance check on Tick, that's 6,000 executions per second. Blueprint runs slower than C++, so that volume hits your frame rate directly.
And the most common beginner use of Tick is polling: checking every single frame to see whether anything changed.
Common mistake: a distance check every frame
Event Tick → Get Distance To (player) → Branch (less than 500?) → do something
For the 99% of the time the player is far away, those distance calculations run for nothing. Stop standing guard, and let someone tell you instead. That's the core of Tick-less design.

Tick-less Design: Three Alternatives
Switching to event-driven logic, where things run only when something happens, comes down to these three tools.

Option 1: Use a Timer for Periodic Work
Work that doesn't need to run every frame but should still run regularly (poison damage over time, an AI re-scanning for targets) belongs to Set Timer by Event.
Event BeginPlay → Set Timer by Event (Time: 0.5, Looping: True)
Event pin ← Custom Event: HealOverTime
HealOverTime → add 1 to Health and Set
Tick at 60 FPS runs 60 times per second. A 0.5-second Timer runs twice. That's 1/30th the number of executions.
Option 2: Use an Event Dispatcher to Watch for State Changes
Instead of checking every frame whether the door opened, the door tells you the moment it opens. The door side just Calls OnDoorOpened when it opens, and anyone who cares just Binds ahead of time. See the Event Dispatcher article for the full implementation pattern.
Option 3: Use Collision Events to Detect Proximity and Contact
This is the correct answer to the "measure distance every frame" problem from the intro. Place a Sphere Collision or a Box trigger, and On Component Begin Overlap fires exactly once, the moment something enters. The physics engine handles the distance math for you in an optimized form.
On Component Begin Overlap (detection Sphere) → check for player → start chasing
On Component End Overlap → stop chasing
Optimizing When You Do Need Tick
Some work genuinely needs to run every frame, like smooth movement or camera control. In that case, optimize how you use it.
- Lower the frequency with Tick Interval: Set
Tick Intervalin the Actor's Details panel (default 0.0 means every frame). For work that tolerates a bit of delay, like target scanning,0.1(ten times per second) is usually plenty - Toggle Tick based on state: Use
Set Actor Tick Enabledto keep Tick alive only while you need it. The pattern is "on while chasing, off while idle." We'll wire up that switch in the hands-on section

Hands-On: Rebuilding a Guard AI So It Can Sleep Completely
To finish, let's combine all three tools plus the Tick switch into a single AI. Think of a stealth game guard, a survival game roaming monster, or a tower defense turret: enemies that don't need to do anything until you get close.

Setup to reproduce this: In an enemy Blueprint called BP_Guard, prepare the following Component and variables.
| Type | Name | Setting |
|---|---|---|
| Component | DetectionSphere (Sphere Collision) | Sphere Radius = 800.0 (detection range) |
| Variable | ChaseTarget (Actor) | No default value. Remembers who to chase |
| Variable | ChaseHandle (Timer Handle) | Saved so the chase Timer can be stopped |
The Before version (the Tick approach) had every enemy measuring distance every frame, and re-issuing the destination every frame with Event Tick → AI Move To. That is polling for both the search and the movement — exactly what this article is telling you to stop doing. In the After version we move the chase onto a Timer as well and rebuild it without a single line of Tick.
-
Start the chase Timer only when something enters: when the detection range is touched, start a chase loop that refreshes the destination every 0.2 seconds

On Component Begin Overlap (DetectionSphere) → Cast To BP_Player (Other Actor) success → Set ChaseTarget (= Other Actor) → Is Timer Active by Handle (ChaseHandle) False → Set Timer by Event (Time: 0.2, Looping: true) Event pin ← Custom Event: ChaseStep → Set ChaseHandle (= Return Value) ← saved so we can stop it ChaseStep (every 0.2 seconds. Not a Tick) → Is Valid (ChaseTarget) Valid → AI Move To (Pawn: self, Destination: ChaseTarget's location)AI Move Tois a node where issuing the move once is enough — the engine keeps the movement going. You don't need to call it again every frame; refreshing the destination to the player's latest position every 0.2 seconds is plenty for a smooth chase. What was 60 destination re-issues per second becomes 5 per second.The
Is Timer Active by Handleguard is there so the chase Timer doesn't stack two or three deep as the player steps in and out of the detection circle. Timers multiplying on re-entry is the single easiest bug to hit with this design.AI Move ToneedsBP_Guardto be a Character (or Pawn) withAuto Possess AIset toPlaced in World or Spawned, and it needs a NavMesh covering the floor it walks on. -
Stop chasing and go to sleep on exit: when the player leaves the range, throw the chase Timer away and leave only the low-frequency patrol Timer
On Component End Overlap (DetectionSphere) → Clear and Invalidate Timer by Handle (Handle = ChaseHandle) ← stop chasing → Set ChaseTarget (= None) → Set Timer by Event (Time: 0.5, Looping: true) Event pin ← Custom Event: LookAround LookAround → light surroundings check (just turning to look around)
Even while chasing, the destination updates 5 times per second; while patrolling, twice. This enemy never uses Event Tick from start to finish. It still feels present, and the cost is close to zero.
One gotcha: if you skip
Clear and Invalidate Timer by Handleand onlySet ChaseTarget (None), the chase Timer keeps running and just spins on a failingIs Validevery time. Any Timer you need to stop should have its Handle saved and be destroyed explicitly.
Hit Play and check. Bump the enemy count to 10, then 50, and as long as you stay outside the detection circles, your frame rate should barely move. Only the enemies whose circle you step into start their chase Timer, and it stops once you leave. Display stat game with the Stats command while comparing before and after, and you can see the difference in Game time as an actual number. Once the chase logic gets complicated, the next step is moving Move To into a proper Behavior Tree task.
Two things to take away.
- Design around controlling how many enemies are awake: Move from "everyone works" to "only the few nearby work." Your cost is then determined not by the total enemy count but by how many are awake at once
- Tick isn't evil, it's a luxury: Tick is the right tool for smooth movement while chasing. Tick-less design isn't about banning it. It's about splurging on it only in the moments that need it
Bonus: Good to Know for Later
- Delay and Timeline are Tick-less too:
Delay(resume after a few seconds) andTimeline(a node that interpolates values over time, great for opening doors and fades) give you time-based behavior without writing any Tick logic (see the delay nodes mentioned in Function vs Macro) - Tick Group is an advanced setting: You can control Tick execution order with
Tick Group(PrePhysics / DuringPhysics / PostPhysics). Remember it exists once you hit a dependency like "I want to process this after the physics results are in" - Don't forget Component Tick: Custom Components have Tick enabled by default. If you don't use it, turn off Start with Tick Enabled (see the Blueprint Component article)
Summary
| Alternative | Use Case | Execution Frequency |
|---|---|---|
| Timer | Periodic work (healing, periodic target scans) | At the interval you set (e.g. every 0.5 seconds) |
| Event Dispatcher | Notifying state changes | Only when the event fires |
| Collision Events | Detecting proximity and contact | Only on entering or leaving |
| Tick Interval / on-off | Work that genuinely needs every frame | Only when needed |
Before you wire anything to Tick, ask: does this really need to run every frame? If no, reach for one of the three tools. If yes, still narrow it down to "only while needed." That alone makes your game noticeably lighter.
When you want hard numbers on your current performance, head to finding bottlenecks with the Stats command.
Can you list every piece of logic currently wired to Event Tick in your project? Go through them one by one and ask whether each really needs every frame. Half of them can probably start sleeping tonight.