Every real time engine — whether for games, physics simulations, or visualization — must solve one fundamental problem:
This article explains:
This is the foundation for the physics module, the renderer, and the entire engine runtime.
Real time engines run in a loop:
while (running) {
process_input();
update();
simulate();
render();
}
But the
Time is not just a number — it is a
There are two main approaches to advancing time.
Each frame uses the actual time elapsed since the previous frame:
float dt = time_now - time_prev;
simulate(dt);
Variable timestep is
Simulation always advances in fixed increments:
const float dt = 1.0f / 60.0f; // 60 Hz simulation
Rendering may run at 144 FPS, but simulation always runs at 60 Hz.
Fixed timestep is
This is the industry standard solution used by:
float accumulator = 0.0f;
float dt = 1.0f / 60.0f;
while (running) {
float frame_time = time_now - time_prev;
time_prev = time_now;
accumulator += frame_time;
while (accumulator >= dt) {
simulate(dt);
accumulator -= dt;
}
render(interpolate(accumulator / dt));
}
The time module belongs in the platform layer because:
namespace btg_platform {
void start_timer(); // initialize timer
double get_elapsed_time(); // get elapsed time in seconds since last call to start_timer or get_elapsed_time
double get_last_elapsed_time(); // get the last elapsed time without resetting the timer
}
std::chrono::high_resolution_clockDeterminism means:
This is essential for:
This is why the engine’s architecture is designed the way it is.
Rendering runs as fast as possible:
Simulation runs at a fixed rate:
Rendering is
Rendering can interpolate. Simulation cannot.
Rendering can skip frames. Simulation must not.
To avoid jitter:
render(interpolate(alpha));
Where:
alpha = accumulator / dt;
This blends between:
This produces smooth motion even when simulation runs slower than rendering.
Here is the final loop that the GusOnGames engine will use:
float accumulator = 0.0f;
const float dt = 1.0f / 60.0f;
while (window.is_open()) {
Time::update();
float frame_time = Time::delta();
accumulator += frame_time;
input.update();
while (accumulator >= dt) {
simulation.update(dt);
accumulator -= dt;
}
float alpha = accumulator / dt;
renderer.render(alpha);
}
This loop is:
This article defined the time system for the GusOnGames engine:
This is one of the most important architectural decisions in the entire engine.