- DelphiTools - https://www.delphitools.info -

Time-stepping for Games and Simulations

Wittner_metronomeThe built-in time-stepping support for the upcoming release of SmartMS [1] got an overhaul in the form of a now frame-rate oriented Game View component, and a simulation-oriented TMetronome time-stepper.

This article quickly discusses the theory, changes, and gives an introduction for use in games and simulations.

Time-Stepping in Simulated Worlds

Time stepping in simulated worlds is a general problem not restricted to games.

Basically, you have to deal with screen updates that take a variable amount of times, not just because what you need to draw (render) on the screen can vary (which would be bad enough), but because the environment introduces latencies (other applications taking CPU time, network lag, storage access times, etc.).

While you sometimes want to render at a high frame-rate, outside of benchmarks, there is no point rendering more frames than the screen can display, as it’ll only waste energy.

magsim1_hOn the simulation side, you usually want some reproduce-ability (if only for debugging and testing), and you want to ensure that while the visuals can depend on the capability of the hardware you’re running on, the simulation shouldn’t depend on the hardware, which means fixed time-steps.

So the general problem is to adapt a variable time-step problem (rendering) with desired synchronization (with screen refresh) and a simulation with fixed time-steps.

A good discussion of the pros and cons can be found in Fixed time step vs Variable time step [2].

Next: Decoupling Refresh Rate from Simulation [3]

Previous: Time-Stepping in Simulated Worlds. [4]

Decoupling Refresh Rate from Simulation

FurBallThat’s usually accomplished by rendering as fast as the hardware can, ideally at the refresh rate [5] (or “VSYNC”, in reference to old CRT display), measuring the time elapsed since the last frame, accumulating that time and advancing the simulation in fixed time-steps.

This also means that you can safely decouple the time-stepping of visual effects and rendering from that of the simulation. The time-stepping of your simulation should be tied to the needs of the physics, while the rendering should be tied to the needs of the eye (or the capability of the hardware).

In practice, for some rendered frames, the simulation may not advance, and for others, it may advance several steps.

miniForestThis can be the case if your simulation is fairly complex, and is only realistically stepped at 15 Hz, while visually you may want a smoother 60 FPS (or more). In those situations:

miniOceanA simulation may (should?) involve multiple sub-simulations, that will run at various time-steps, for instance in a game you could have:

This is a simple way to focus processing resources on simulated aspects the protagonist(s) will see and interact with.

Next: A Smarter Game View [6]

Previous: Decoupling Refresh Rate from Simulation. [3]

Updated Game View

NickelIron_shot [7]Previously the TW3GameView was simply trying to issue screen repaints at fixed intervals, what happened if the hardware couldn’t keep up (or could have rendered faster) was your problem.

The new TW3GameView now has several modes:

Additionally, the view will now automatically suspend repaints if the view goes off-screen (application going to background in a mobile app, tab switch in a browser). I you don’t want that and still want the repaints to occur, just set the AutoPause property to False.

In addition, the overhead of the game view got reduced and the accuracy of frame-rate measurement got improved, and a LastFrameTime provides high-precision measurement for the time since the last frame was rendered.

In terms of Web Standards, the new game view leverages the following APIs:

These API have widespread support, and if not available, the view will automatically fallback to legacy approaches.

Next: Fix Your Steps with a Metronome [11]

Previous: A Smarter Game View. [6]

The new TMetronome

Wittner_metronomeA new class TMetronome in System.Metronome allows to obtain fixed time steps from the variable time-steps of the game view repaints (or any other variable time-steps, TMetronome is an independent class).

You just need to create a TMetronome class, initialize it, feed it your variable time steps, and you’ll get fixed-time steps (“ticks”) in it OnProgress event. A typical use case will look like:

procedure TYourApplication.ApplicationStarting;
begin
   ...
   FMetronome := TMetronome.Create;
   FMetronome.TickFrequency := 100;               // run simulation at 100 Hz
   FMetronome.OnProgress := DoSimulationProgress; // fixed time-steps events there
end;

procedure TYourApplication.PaintView(Canvas:TW3Canvas);
begin
   // we come here in variable time-steps
   // we pass the variable time elapsed since the last frame to the metronome
   // which will generate fixed time steps for DoSimulationProgress
   FMetronome.Progress(GameView.LastFrameTime);
   ...
   // paint your view here
end;

Sometimes the hardware may just not be able to keep up (if just temporarily), and you may be faced with having to either stall the simulation, or just skip ahead.

The threshold for that is determined by the MaxTicksPerProgress property, and what to do by the ProgressPolicy, which can be used to determine if you’ll Stall the simulation (Ticks won’t advance by more than MaxTicksPerProgress), or just Skip ahead.

You can have as many metronomes as you want, and then you can let every simulation progress at its own rythm:

FMetronomes : array of TMetronome;
...
for var metronome in FMetronomes do
   metronome.Progress(lastFrameTime);

This will hopefully simplify mix’n’matching different simulations in the same world, and you can easily and independently adjust the frequency at which everything progresses.