Advertisement

Game loop tick count

Started by January 16, 2014 10:58 AM
9 comments, last by Grey Temchenko 10 years, 10 months ago

Hi there, the most common way to implement game loop around internet is


const int FPS = 25;
const int FrameDuration = 1000 / FPS;
const int MaxFrameSkip = 5;
long nextFrameTime = time();
 
float interpolation;
int loops;
 
while( isGameRunning )
{
    loops = 0;
    while( time() > nextFrameTime && loops < MaxFrameSkip )
    {
        updateGameState();
        
        nextFrameTime += FrameDuration;
        
        loops++;
    }

    interpolation = .....;
    
    render(interpolation);
}

The author says that updateGameState() calls 25 times per second, now less, no more. In my mind this mean that while should run 25 times. Am i wrong? According to loops variable there is restriction on 5 runs. So how there can be 25 times per second?

And if this mean, that user input catch inside updateGameState also 25 times\sec?

The outer while loop will run many times during a single second. The idea here is that render() is called as many times as possible to maintain a very high frame rate. In between these calls to render(), the game state will be updated via the inner while loop. The idea is that the inner while loop may run zero, one, or perhaps multiple times per outer loop execute depending on whether its ahead, right on time, or has fallen behind due to heavy rendering respectively. But that inner while loop will only tick 25 times during a single second and is designed to only run up to a maximum of 5 times if its fallen behind. This is so that you don't get heavy drops in frame rates if the rendering is taking considerably longer than it should.

Advertisement

The author is fibbing very slightly -- if your computer cannot render (25 / MaxFrameSkip) frames AND simulate 25 frames in one second, then it will call the simulation function less than 25 times in a second.

Else, it will call the simulation function 25 times, and render as many frames as it can, in a second.

enum Bool { True, False, FileNotFound };

So if my computer able to run with >= 25 frames\sec this mean updateGameState will call 25 times\sec? Should i get user input inside updateGameState? Because if this loop really runs 25 times i can change, for example client position on speed \ 25. And render with prediction to smooth movement. This mean after 25 loops it move on full speed location. But if computer unable to support this 25 frames, i'll get random count of loop runs? How then i can calculate speed for every step?


time_old = get_time();
time_acc = 0;
time_now = 0;
time_delta = 0;

while (true) {
    time_now = get_time();
    time_delta = time_now - time_old;
    time_old = time_now;


    // limit max delta so we dont spiral away
    if (time_delta > 0.25) {
        time_delta = 0.25;
    }

    time_acc += time_delta;

    while (time_acc >= (1f / 60f)) {
        simulate();
        time_acc -= (1f / 60f);
    }

    render(time_delta);
}

This is the canonical game-loop with a fixed simulation step as I learned it smile.png

Wow that something new... I still can't grasp my example, and here is new one, this blow my mind) What the difference?

Advertisement

Both approaches implement the same effect.

The simulation will be called a fixed number of times per real second (25 in your case, 60 in the second case.)

The render function will be called more, fewer, or the same number of times as the simulation function, depending on how fast your computer and graphics card is.

The end result is that the simulation will always proceed at the correct tick rate relative to real time, unless your computer is so slow that it can't even render a few frames per second.

I suggest you walk through the two code snippets in your head, or even better on paper/whiteboard, keeping a running tally of what the values of the different times/variables are. Keep a special "variable" called "the real time." To know how fast "the real time" advances, you can assume that the simulation tick takes 0.001 seconds, and that rendering a frame takes 0.01 seconds, for example. Or, for a slower computer, 0.003 seconds for simulation, and 0.1 seconds for rendering.

Once you walk through these loops, you should get a sense for how often/seldom a frame is interpolated and rendered, and how many/few simulation ticks get executed between each frame of rendering.

enum Bool { True, False, FileNotFound };

void Game::FixedStepLoop(){

	// update timer
	m_timer.Update();

	// get time since last timer update
	double dDeltaSeconds = m_timer.GetDeltaSeconds();

	// cap to max frame delay allowed, this is to avoid spiral of death
	if( dDeltaSeconds > m_dMaxFrameTimeDelay ) dDeltaSeconds = m_dMaxFrameTimeDelay;

	// add the delta to the delta remained from previous updates (deltas not used)
	static double dFrameDeltaRemainingsAccumulated = 0.0;
	dFrameDeltaRemainingsAccumulated += dDeltaSeconds;

	// perform updates by fixed steps, any time remaining will accumulate to the next iteration
	// any time missing will skip the update till a fix step amount is reached

	while( dFrameDeltaRemainingsAccumulated >= m_dFixedTimeStep ){

		// consume the fixed amount from the accumulated buffer
		dFrameDeltaRemainingsAccumulated -= m_dFixedTimeStep;

		m_stateControl.Update( m_dFixedTimeStep );
	}

	// compute the interpolation factor based on the remaining timing
	// the interpolation is used to fix rendering motion across the discrete update steps
	const double dInterpolationAmount = dFrameDeltaRemainingsAccumulated/m_dFixedTimeStep;

	// draw

	m_stateControl.Draw( dInterpolationAmount );
}

Heres a very verbose fixed step game loop, hope it helps more than confuses (and that it is correct)

At home i have a link to site with nice pictures that describe what you say

I suggest you walk through the two code snippets in your head, or even better on paper/whiteboard, keeping a running tally of what the values of the different times/variables are. Keep a special "variable" called "the real time." To know how fast "the real time" advances, you can assume that the simulation tick takes 0.001 seconds, and that rendering a frame takes 0.01 seconds, for example. Or, for a slower computer, 0.003 seconds for simulation, and 0.1 seconds for rendering.

If i have code that supports 100fps(for example) and can run update loop 25 times\sec, that ok. But if sometimes in some scenes update will take much time, and it can't run 25 times, instead it make 15\sec updates or 5\sec... Is it real? Or these methods resolve this trouble with accumulate variable?

if sometimes in some scenes update will take much time, and it can't run 25 times


If by "update" you mean that you physical simulation cannot proceed at real time, then your game is broken and will not work.
For example, if you want to simulate at 25 Hz (40 ms per step,) but your physics update function takes 50 milliseconds, then you will never be able to simulate based on real time.

If, however, most simulation steps take 10 milliseconds, but one or two steps take 60 milliseconds on occasion, then the loop structure that all of these loops implement will properly deal with that.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement