Different Update Rates for Game Objects

Is it possible to have different objects in the game world update at different rates?

Yes, it's absolutely possible to have different objects in the game world update at different rates. This technique can be useful for optimizing performance, creating interesting gameplay effects, or simulating systems with different time scales. Let's explore how we can implement this:

Using Timers for Different Update Rates

One approach is to use timers for each object or group of objects that need to update at a different rate. Here's an example:

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

class GameObject {
public:
  virtual void update(float dt) = 0;
  virtual ~GameObject() = default;
};

class FastObject : public GameObject {
public:
  void update(float dt) override {
    // Update logic for fast objects
    std::cout << "Fast object updated\n";
  }
};

class SlowObject : public GameObject {
public:
  void update(float dt) override {
    // Update logic for slow objects
    std::cout << "Slow object updated\n";
  }
};

class World {
private:
  std::vector<std::unique_ptr<
    GameObject>> objects;
  float fastUpdateTimer = 0.0f;
  float slowUpdateTimer = 0.0f;

  // 20 times per second
  const float FAST_UPDATE_INTERVAL = 0.05f;
  // 2 times per second
  const float SLOW_UPDATE_INTERVAL = 0.5f;

public:
  void addObject(
    std::unique_ptr<GameObject> obj) {
    objects.push_back(std::move(obj));
  }

  void update(float dt) {
    fastUpdateTimer += dt;
    slowUpdateTimer += dt;

    if (fastUpdateTimer >=
      FAST_UPDATE_INTERVAL) {
      for (auto& obj : objects) {
        if (dynamic_cast<FastObject*>(obj.
          get())) {
          obj->update(fastUpdateTimer);
        }
      }
      fastUpdateTimer = 0.0f;
    }

    if (slowUpdateTimer >=
      SLOW_UPDATE_INTERVAL) {
      for (auto& obj : objects) {
        if (dynamic_cast<SlowObject*>(obj.
          get())) {
          obj->update(slowUpdateTimer);
        }
      }
      slowUpdateTimer = 0.0f;
    }
  }
};

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_VIDEO);
  World gameWorld;
  gameWorld.addObject(
    std::make_unique<FastObject>());
  gameWorld.addObject(
    std::make_unique<SlowObject>());

  Uint64 previousTime = SDL_GetTicks64();
  while (true) {
    Uint64 currentTime = SDL_GetTicks64();
    float dt = (currentTime - previousTime) /
      1000.0f;
    previousTime = currentTime;

    gameWorld.update(dt);

    SDL_Delay(16); // Roughly 60 FPS
  }

  SDL_Quit();
  return 0;
}
Fast object updated
Fast object updated
Fast object updated
Fast object updated
Slow object updated
Fast object updated
Fast object updated
...

In this example, FastObject instances update 20 times per second, while SlowObject instances update only 2 times per second.

Using Update Counters

Another approach is to use update counters for each object:

class GameObject {
protected:
  int updateFrequency;
  int updateCounter = 0;

public:
  GameObject(int freq) : updateFrequency(freq) {
  }

  virtual void update(float dt) {
    updateCounter++;
    if (updateCounter >= updateFrequency) {
      updateCounter = 0;
      performUpdate(dt * updateFrequency);
    }
  }

  virtual void performUpdate(float dt) = 0;
};

class FastObject : public GameObject {
public:
  // Update every frame
  FastObject() : GameObject(1) {}

  void performUpdate(float dt) override {
    // Fast update logic here
  }
};

class SlowObject : public GameObject {
public:
  // Update every 10 frames
  SlowObject() : GameObject(10) {}

  void performUpdate(float dt) override {
    // Slow update logic here
  }
};

This approach allows for more flexibility in setting update frequencies and doesn't require separate timers for each update rate.

Considerations

When implementing different update rates, keep these points in mind:

  1. Consistency: Ensure that the behavior of objects is consistent regardless of their update rate.
  2. Interpolation: For visual smoothness, you might need to interpolate between updates for slow-updating objects.
  3. Physics: Be cautious when applying different update rates to physics objects, as it can lead to inconsistencies or instabilities.
  4. Performance: While this can optimize performance, be mindful of the overhead introduced by the system itself.

By implementing different update rates for game objects, you can create more efficient and dynamic game worlds, tailoring the update frequency to the needs of each object or system in your game.

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?
Smooth Acceleration and Deceleration
How can we create smooth acceleration and deceleration effects using time deltas?
Alternatives to SDL_Delay()
What are some alternatives to SDL_Delay() for more precise timing control?
Or Ask your Own Question
Purchase the course to ask your own questions