In this lesson, you will learn how to reduce CPU overhead by refactoring logic-heavy per-frame calculations into decoupled timer-based execution cycles.
The Problem with "Every Frame"
The Tick function is executed every single frame. If you have 50 actors performing complex calculations—like scanning for nearby targets or updating UI data—every frame, you are forcing the Game Thread to perform that work 60 to 144+ times per second regardless of necessity. This leads to erratic frame times and unnecessary performance spikes.
The Timer Solution
Most gameplay logic does not require millisecond-perfect synchronization with the monitor's refresh rate. By moving non-critical logic to a FTimerHandle, you can control exactly how often code executes (e.g., 5 times per second rather than 60). This distributes the load across frames, smoothing out the CPU usage.
Consider this common optimization pattern:
// Instead of doing this in Tick:
void AMyActor::Tick(float DeltaTime) {
Super::Tick(DeltaTime);
PerformHeavyCalculation(); // Running 60+ times/sec
}
// Do this using a Timer:
void AMyActor::BeginPlay() {
Super::BeginPlay();
GetWorldTimerManager().SetTimer(MyTimerHandle, this, &AMyActor::PerformHeavyCalculation, 0.2f, true);
}
By setting the interval to 0.2f, you execute your heavy logic only five times per second. This is imperceptible to the player for most gameplay systems (like updating an enemy’s target state or refreshing a quest tracker) but drastically reduces the function’s impact on your performance baseline.
Managing Performance
When you transition to timer-based loops, you gain the ability to "jitter" your timers. If you have 100 actors all using the same 0.2s interval, they might all trigger on the exact same frame, creating a micro-spike. To avoid this, add a small random initial delay to your SetTimer calls:
float RandomDelay = FMath::FRandRange(0.0f, 0.2f);
GetWorldTimerManager().SetTimer(MyTimerHandle, this, &AMyActor::PerformHeavyCalculation, 0.2f, true, RandomDelay);
This spreads the workload across the timeline, keeping your frame times consistent and predictable.
Key Takeaway: Moving logic from Tick to a Timer allows you to execute code at the minimum necessary frequency, significantly reducing Game Thread pressure.