High-Resolution Timers

Using Low-Resolution Timers in Games

Are there any situations where using lower resolution timers might be preferable?

Abstract art representing computer programming

While high-resolution timers are generally preferred in game development for their precision, there are indeed situations where lower resolution timers might be more appropriate. Let's explore some of these scenarios:

Resource Conservation

Lower resolution timers, like SDL_GetTicks64(), typically consume fewer system resources than high-resolution timers. This can be beneficial in certain situations:

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

void lowResolutionExample() {
  Uint64 start{SDL_GetTicks64()};

  // Simulate work
  SDL_Delay(100);

  Uint64 end{SDL_GetTicks64()};
  std::cout << "Time elapsed: "
    << (end - start);
}

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_TIMER);
  lowResolutionExample();
  SDL_Quit();
  return 0;
}
Time elapsed: 100ms

This approach is less taxing on the CPU, which can be crucial for:

  1. Mobile devices where battery life is a concern.
  2. Games with low performance requirements that don't need high precision.
  3. Background processes or less critical game systems.

Simplified Logic

For game mechanics that don't require high precision, using lower resolution timers can simplify your code:

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

class PowerUp {
  Uint64 spawnTime;
  const Uint64 duration{10000}; // 10 seconds

public:
  PowerUp() : spawnTime{SDL_GetTicks64()} {}

  bool isActive() {
    return (SDL_GetTicks64() - spawnTime) <
      duration;
  }
};

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

  PowerUp powerUp;
  std::cout << "Power-up active: " <<
    std::boolalpha << powerUp.isActive()
    << '\n';

  SDL_Delay(11000); // Wait 11 seconds
  std::cout << "Power-up active: "
    << powerUp.isActive() << '\n';

  SDL_Quit();
  return 0;
}
Power-up active: true
Power-up active: false

This example uses SDL_GetTicks64() for a power-up duration. Millisecond precision is more than adequate for this purpose, and the code is straightforward.

Compatibility and Legacy Systems

Some older systems or APIs might not support high-resolution timers. In these cases, using lower resolution timers ensures broader compatibility:

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

void compatibleTimingFunction() {
#if SDL_VERSION_ATLEAST(2, 0, 18)
  Uint64 ticks{SDL_GetTicks64()};
#else
  Uint32 ticks{SDL_GetTicks()};
#endif
  std::cout << "Ticks: " << ticks << '\n';
}

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_TIMER);
  compatibleTimingFunction();
  SDL_Quit();
  return 0;
}

Network Synchronization

In networked games, the latency of network communications often makes high-resolution timers unnecessary. Using lower resolution timers can simplify network code:

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

struct NetworkPacket {
  Uint32 timestamp;
  // Other packet data...
};

NetworkPacket createPacket() {
  NetworkPacket packet;
  // 32-bit timestamp is often sufficient
  packet.timestamp = SDL_GetTicks();
  return packet;
}

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

  NetworkPacket packet = createPacket();
  std::cout << "Packet timestamp: "
    << packet.timestamp << "ms\n";

  SDL_Quit();
  return 0;
}
Packet timestamp: 0ms

Reduced Precision Requirements

Some game systems don't require high precision. For example, a day/night cycle in a game might work perfectly well with second-level precision:

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

class DayNightCycle {
  Uint64 cycleStartTime;
  // 5 minutes (300,000 ms)
  const Uint64 cycleDuration{300000};

public:
  DayNightCycle() : cycleStartTime{
    SDL_GetTicks64()} {}

  float getDayProgress() {
    Uint64 elapsedTime{
      (SDL_GetTicks64() - cycleStartTime) %
      cycleDuration};

    return static_cast<float>(elapsedTime) /
      cycleDuration;
  }
};

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

  DayNightCycle cycle;
  std::cout << "Day progress: "
    << cycle.getDayProgress();

  SDL_Delay(150000); // Wait 2.5 minutes
  std::cout << "\nDay progress: "
    << cycle.getDayProgress();

  SDL_Quit();
  return 0;
}
Day progress: 0
Day progress: 0.5

In this case, millisecond precision from SDL_GetTicks64() is more than adequate, and using a higher resolution timer wouldn't provide any noticeable benefit.

While high-resolution timers are crucial for many aspects of game development, it's important to choose the right tool for each job. By using lower resolution timers where appropriate, you can often simplify your code, improve performance, and ensure broader compatibility without sacrificing necessary precision.

This Question is from the Lesson:

High-Resolution Timers

Learn to measure time intervals with high accuracy in your games

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

High-Resolution Timers

Learn to measure time intervals with high accuracy in your games

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 71 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved