SDL Timers vs Frame Counting
Why might I want to use SDL timers instead of just counting frames in the main game loop for timing events?
SDL timers offer several important advantages over frame counting for game events. Let's explore why you might choose one over the other.
Accuracy and Consistency
Frame-based timing can be problematic because frame rates often fluctuate. Consider this frame-counting approach:
#include <SDL.h>
#include <iostream>
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* Window = SDL_CreateWindow(
"Frame Timer", 100, 100, 800, 600, 0);
int FrameCount{0};
// Spawn every 60 frames
const int SpawnInterval{60};
while (true) {
// Process events...
SDL_PumpEvents();
FrameCount++;
if (FrameCount % SpawnInterval == 0) {
std::cout << "Spawning enemy at frame "
<< FrameCount << '\n';
}
// Render scene...
// Simulate varying frame times
SDL_Delay(16);
}
SDL_DestroyWindow(Window);
SDL_Quit();
return 0;
}
Spawning enemy at frame 60
Spawning enemy at frame 120
Spawning enemy at frame 180
Spawning enemy at frame 240
If your game runs at 60 FPS, enemies spawn every second. But if it drops to 30 FPS, enemies spawn every 2 seconds! With SDL timers, spawning remains consistent regardless of frame rate:
#include <SDL.h>
#include <iostream>
Uint32 SpawnEnemy(Uint32 Interval, void*) {
std::cout << "Spawning enemy at time "
<< SDL_GetTicks() << "ms\n";
return Interval;
}
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
SDL_Window* Window = SDL_CreateWindow(
"SDL Timer", 100, 100, 800, 600, 0);
SDL_AddTimer(1000, SpawnEnemy, nullptr);
while (true) {
// Process events...
SDL_PumpEvents();
// Render scene...
// Varying frame times don't affect spawn rate
SDL_Delay(16);
}
SDL_DestroyWindow(Window);
SDL_Quit();
return 0;
}
Spawning enemy at time 1090ms
Spawning enemy at time 2090ms
Spawning enemy at time 3090ms
Spawning enemy at time 4090ms
System Resource Usage
Frame counting requires checking conditions every frame, even for events that happen rarely. SDL timers only consume resources when they actually trigger, making them more efficient for:
- Long intervals (like buff duration timers)
- Multiple concurrent timers with different intervals
- Events that need precise timing
Thread Safety
SDL timers run on a separate thread, meaning they:
- Won't be delayed by heavy processing in your game loop
- Can trigger during loading screens or other blocking operations
- Can handle system events even when your main thread is busy
The downside is you need to be careful about thread safety when modifying shared data in callbacks.
When to Use Each
Use SDL timers for:
- Events that need precise timing (combos, buff durations)
- Background tasks (autosave, network polling)
- Events that should continue during pauses/loading
Use frame counting for:
- Visual effects tied to animation frames
- Game mechanics that should intentionally slow down with frame rate
- Simple cooldowns that don't need precise timing
Remember, you can also combine both approaches where appropriate!
SDL2 Timers and Callbacks
Learn how to use callbacks with SDL_AddTimer()
to provide functions that are executed on time-based intervals