Alternatives to SDL_Delay()

What are some alternatives to SDL_Delay() for more precise timing control?

While SDL_Delay() is a simple way to introduce pauses in your game loop, it's not always the most precise or efficient method for timing control. Here are some alternatives that can provide more accurate timing:

SDL_AddTimer()

SDL provides a timer mechanism that can call a callback function at specified intervals. This can be more precise than SDL_Delay():

#include <SDL.h>
#include <iostream>

Uint32 timerCallback(Uint32 interval,
                     void* param) {
  std::cout << "Timer fired at " <<
    SDL_GetTicks64() << " ms\n";
  // Return the same interval to
  // keep the timer going
  return interval;
}

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_TIMER);

  SDL_TimerID timerId = SDL_AddTimer(
    100, timerCallback, nullptr);

  // Main loop
  for (int i = 0; i < 50; ++i) {
    // Just to keep the program running
    SDL_Delay(10);
  }

  SDL_RemoveTimer(timerId);
  SDL_Quit();
  return 0;
}
Timer fired at 100 ms
Timer fired at 200 ms
Timer fired at 300 ms
Timer fired at 400 ms
Timer fired at 500 ms
...

This approach allows you to perform actions at regular intervals without blocking the main thread.

High Resolution Timer

For more precise timing, you can use SDL's high resolution timer functions:

#include <SDL.h>
#include <iostream>

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_TIMER);

  Uint64 performanceFrequency =
    SDL_GetPerformanceFrequency();
  Uint64 start = SDL_GetPerformanceCounter();

  // Simulate some work
  for (int i = 0; i < 1000; ++i) {
    std::cout << "Working...\n";
  }

  Uint64 end = SDL_GetPerformanceCounter();
  double elapsed = (end - start) / static_cast<
    double>(performanceFrequency);

  std::cout << "Elapsed time: " << elapsed <<
    " seconds\n";

  SDL_Quit();
  return 0;
}
...
Working...
Working...
Elapsed time: 0.0356943 seconds

This method provides nanosecond precision, which is much more accurate than SDL_GetTicks64().

Busy Waiting

For extremely precise timing, you can use a busy-wait loop. However, this approach uses 100% CPU while waiting:

#include <SDL.h>
#include <iostream>

void preciseSleep(double seconds) {
  Uint64 performanceFrequency =
    SDL_GetPerformanceFrequency();
  Uint64 start = SDL_GetPerformanceCounter();

  while (true) {
    Uint64 now = SDL_GetPerformanceCounter();
    double elapsed = (now - start) / static_cast
      <double>(performanceFrequency);
    if (elapsed >= seconds) { break; }
  }
}

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_TIMER);

  std::cout << "Starting at " <<
    SDL_GetTicks64() << " ms\n";
  preciseSleep(0.1); // Sleep for 0.1 seconds
  std::cout << "Ended at " << SDL_GetTicks64()
    << " ms\n";

  SDL_Quit();
  return 0;
}
Starting at 0 ms
Ended at 100 ms

This method provides very precise timing but at the cost of high CPU usage.

std::chrono

C++'s standard library provides the <chrono> header, which offers high-precision timing facilities:

#include <SDL.h>
#include <chrono>
#include <iostream>
#include <thread>

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_TIMER);

  auto start =
    std::chrono::high_resolution_clock::now();

  // Sleep for 100 milliseconds
  std::this_thread::sleep_for(
    std::chrono::milliseconds(100));

  auto end =
    std::chrono::high_resolution_clock::now();
  std::chrono::duration<double> elapsed = end -
    start;

  std::cout << "Elapsed time: " << elapsed.
    count() << " seconds\n";

  SDL_Quit();
  return 0;
}
Elapsed time: 0.100734 seconds

This method combines high precision with the ability to sleep without consuming CPU resources.

When choosing an alternative to SDL_Delay(), consider the trade-offs between precision, CPU usage, and complexity. For most games, a combination of SDL_AddTimer() for regular updates and std::chrono for precise measurements often provides a good balance of accuracy and efficiency.

Tick Rate and Time Deltas

Learn how to create smooth, time-aware game loops that behave consistently across different hardware configurations

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Handling Large Time Deltas
How can we handle very large time deltas that might occur if the game is paused or minimized?
Fixed vs Variable Time Step
What are the pros and cons of using a fixed time step versus a variable time step?
Different Update Rates for Game Objects
Is it possible to have different objects in the game world update at different rates?
Smooth Acceleration and Deceleration
How can we create smooth acceleration and deceleration effects using time deltas?
Or Ask your Own Question
Purchase the course to ask your own questions