Jump to content
  • Advertisement
Sign in to follow this  
Deftwun

Game Loop & FrameRate Control Opinions

This topic is 2555 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I've been looking at different ways of implementing constant framerates and the like. I've seen a lot of different implementations most seeming a little more thought out than mine. It's what I've always done because it seems so simple but I'd like some advice/criticisms.

Here's the gist:


//Render Rate
float RenderRate = 60;
sf::Clock RenderTimer;
RenderTimer.Reset();

//Physics rate
float PhysicsRate =60;
sf::Clock PhysicsTimer;
PhysicsTimer.Reset();

while (GameIsRunning){

//Physics
if (PhysicsTimer.GetElapsedTime() >= (1/PhysicsRate)){
PhysicsWorld.Step(1/PhysicsRate);
PhysicsTimer.Reset();
}

//Render
if (RenderTimer.GetElapsedTime() >= (1/RenderRate)){
mWindow.Clear(sf::Color::White);

for (int x =0; x < mEntityList.size(); x++){
mEntityList[x]->Render(&RenderWindow);
}

mWindow.Display();
RenderTimer.Reset();
}

}//... end loop



My big concern is that there is no defined 'Frame' that... I guess contains the Render and Physics calls. They just kinda do their own thing on their own time. I have made a couple basic game prototypes so far but have only really run them on my PC and an 'ok' laptop. I didn't seem to have any glaring problems. Just looking for some possible pitfalls that I might not think of till later on.

Share this post


Link to post
Share on other sites
Advertisement
So, you're possibly updating your physics and rendering systems on different frames? I don't see the point, and I don't think it's doing what you think it is.

What good is updating the rendering if the objects haven't moved? Isn't that what would happen if you update the rendering twice, without updating the physics?
And, on the other side, if you update physics twice without updating rendering, you may not properly draw some interaction.

If you are trying to used a fixed frame-rate, then your you should start your timer, run physics AND rendering systems, wait proper time to expire since you last started the updates (16.66 mS for 60 FPS), then start over.

Share this post


Link to post
Share on other sites
Thanks. You make a good point. There Is no point in rendering faster than the physics. But I was thinking more if the physics were to update slightly faster then the render rate. That way maybe the physics engine is updated every frame but is only rendered every 3 or something. Just to be able to fine tune on a larger project. With say different render modes or whatever. I haven't done much work with physics engines (i'm learning box2d) So I'm just thinking about how, with the addition of AI, game logic, rendering, etc everything will look and feel (and maybe find CPU hogs). Just to have a little more control. But again I haven't gotten down a complete large project yet, so I'm just wondering what some drawbacks/advanteges/alternatives there may be.

Share this post


Link to post
Share on other sites

So, you're possibly updating your physics and rendering systems on different frames? I don't see the point, and I don't think it's doing what you think it is.

What good is updating the rendering if the objects haven't moved? Isn't that what would happen if you update the rendering twice, without updating the physics?
And, on the other side, if you update physics twice without updating rendering, you may not properly draw some interaction.

If you are trying to used a fixed frame-rate, then your you should start your timer, run physics AND rendering systems, wait proper time to expire since you last started the updates (16.66 mS for 60 FPS), then start over.

It is standard to update rendering and physics at different rates.
Physics at a fixed rate for stability, usually around 30 times per second.

Rendering is done as often as possible.

The reason objects still move smoothly at 60 frames per second is because their render positions are being interpolated between their most recent position and the position before that.
This means everything you see lags behind by, for example, 30 milliseconds, but you can’t notice it, and it allows smooth movement at any framerate.


L. Spiro

Share this post


Link to post
Share on other sites
oh ok so your saying there is benefit to rendering faster than physics. Yeah I suppose stepping physics faster may result in some jitters and stutters and having the rendering just draw whatever it can as fast as it can would have the opposite effect. So do you think this implementation would maintain a more or less constant physics time step? I can kind of see a situation where maybe the physics rate is set at 30 milliseconds but maybe takes 32milliseconds to finish stepping. I'm thinking though that you would need to be using a whole lot of CPU for this to happen. Again I guess it would depend largely on the project.

Share this post


Link to post
Share on other sites
So I guess the thing that really has me scratching my head... is how do i calculate my total frame time. What is a good benchmark to judge how the application is running as a whole? What frame rate am I calculating?

My first thought was to just calculate the time between game loop iterations:


///FPS Calculations
float FrameRateList[FPS_CALC_BUFFER]; //Container holds previous FrameRates
for (int x = 0; x < FPS_CALC_BUFFER; x++) FrameRateList[x] = 0; //zero out buffer
float PrevFrameTime = 0; //Time of last frame
float FrameRate = 0; //Current FrameRate
int ListIndex = 0; //Frame rate buffer index (increments every frame)

///Game Loop
while (SimTimer.GetElapsedTime() < RUN_TIME){

//FPS Calculation
FrameRate = 1/(SimTimer.GetElapsedTime() - PrevFrameTime); //calculate this frames rate
PrevFrameTime = SimTimer.GetElapsedTime(); //save this frames timestamp for next frame
FrameRateList[ListIndex] = FrameRate; //add framerate to list
if (++ListIndex == FPS_CALC_BUFFER) ListIndex = 0; //increment list index (start at beginning if we've hit the limit)

//physics
if (PhysicsTimer.GetElapsedTime() >= (1/PHYSICS_RATE)){
mWorld.Step(1/PHYSICS_RATE,6,2); //step the world
PhysicsTimer.Reset();
}

//Render
if (RenderTimer.GetElapsedTime() >= (1/RENDER_RATE)){
mWindow.Clear(sf::Color::White);
//draw some stuff
mWindow.Display();
RenderTimer.Reset();
}

//debug
if (DebugTimer.GetElapsedTime() >= (1/DEBUG_RATE)){
//Calculate the average of all the framerates in the buffer
//... and output to console
DebugTimer.Reset();
}

}//... end loop


But does this make sense at all really? I get a ridiciously high average (>100,000) but I figure that makes since since the Loop just goes as fast as it can and the other calls (render,physics,debug) aren't always called.

So how could I judge how fast/consistent the game SYSTEM as a whole is doing?
What do people normally do and what does one generally refer to when they say "the engine runs at 60 FPS"

Share this post


Link to post
Share on other sites
Only if your render step makes an effort to interpolate between physics update steps is there any reason to render faster than you update. Displaying two identical images in a row for half a second each is the same as displaying one image for a full second. I don't know if Box 2D allows you to do this easily. (Never used it) If you are not making this effort, then there is no point in doing a new render if you haven't done a physics update to cause a change to the screen image.

In some physics heavy AAA titles, physics will actually be updated many more times per frame than a render or other update. This done gain a better approximation of the curves objects trace as they interact; Forza 3 I believe runs a physics update at 300hz, render at 60 hz to match the display refresh. There are many methods of maintaining numerical stability in a physics simulation; small time steps can help.

Supreme Commander on the other hand only updates it's simulation at 10 hz. Changes to the state of the world, (unit orders, etc.) are actually only updated 10 times a second; units are updated once per frame to interpolate between simulation updates, so they appear to move smoothly through the environment. Supreme Commander does this to make it possible to synchronize the thousands of entities that can exist in a multiplayer game across the network; without the long intervals it would not be possible to keep all clients in sync. (and even then it can break down sometimes).

There are many ways to construct a game loop; if you are just starting to learn then sticking with a simple 'update then render' loop is probably fine. No need to get into simulate->update->render or multi-threaded update unless you are specifically interested in learning them or your project demands it.

Share this post


Link to post
Share on other sites

So I guess the thing that really has me scratching my head... is how do i calculate my total frame time. What is a good benchmark to judge how the application is running as a whole? What frame rate am I calculating?

Use QueryPerformanceFrequency() and QueryPerformanceCounter() to create a timer class that can represent time in microseconds. Time must be maintained in integer form, not floating-point.
At the start of every frame you update the timer, which itself keeps track of the previous time it had along with the new time. The amount of time between updates can be calculated easily.
If you update once per frame you can use this information to keep track of how much time has passed since the last frame.



My first thought was to just calculate the time between game loop iterations:


///FPS Calculations
float FrameRateList[FPS_CALC_BUFFER]; //Container holds previous FrameRates
for (int x = 0; x < FPS_CALC_BUFFER; x++) FrameRateList[x] = 0; //zero out buffer
float PrevFrameTime = 0; //Time of last frame
float FrameRate = 0; //Current FrameRate
int ListIndex = 0; //Frame rate buffer index (increments every frame)

///Game Loop
while (SimTimer.GetElapsedTime() < RUN_TIME){

//FPS Calculation
FrameRate = 1/(SimTimer.GetElapsedTime() - PrevFrameTime); //calculate this frames rate
PrevFrameTime = SimTimer.GetElapsedTime(); //save this frames timestamp for next frame
FrameRateList[ListIndex] = FrameRate; //add framerate to list
if (++ListIndex == FPS_CALC_BUFFER) ListIndex = 0; //increment list index (start at beginning if we've hit the limit)

//physics
if (PhysicsTimer.GetElapsedTime() >= (1/PHYSICS_RATE)){
mWorld.Step(1/PHYSICS_RATE,6,2); //step the world
PhysicsTimer.Reset();
}

//Render
if (RenderTimer.GetElapsedTime() >= (1/RENDER_RATE)){
mWindow.Clear(sf::Color::White);
//draw some stuff
mWindow.Display();
RenderTimer.Reset();
}

//debug
if (DebugTimer.GetElapsedTime() >= (1/DEBUG_RATE)){
//Calculate the average of all the framerates in the buffer
//... and output to console
DebugTimer.Reset();
}

}//... end loop


Your logic is flawed.
Let’s assume logical updates (which include physics) happen every 30 milliseconds.
You keep track of the time of the last update, and each frame you check to see if 30 milliseconds have passed, after which you perform a logical update.
What happens if 70 milliseconds have passed?
You will perform one update instead of the necessary 2.

int logicalUpdatesNeededThisTick = (currentTime - lastUpdateTime) / logicalUpdateInterval; // logicalUpdateInterval = 30.
while ( logicalUpdatesNeededThisTick-- ) {
// Advance logical timer by a fixed amount.
m_logicTimer.UpdateBy( logicalUpdateInterval * 1000ULL ); // 30 microseconds.
TickLogic(); // Handles physics and all logical updating.
}



Another flaw in your logic is that you are simply setting the last update time to whatever the current time is.
Going back to my example, let’s say for the sake of simplicity that we start at t = 0, and the first frame took 70 milliseconds.
Using my above fix you will update twice, which is correct.
But then you set the last update time to the current time, which is 70. That means your next logical update will happen at t = 100, when it should be at t = 90. You have lost 10 milliseconds.

Each time you update the logic, increase the “last logical update time” by the amount that each logical update represents. That would be 30 in my example case.
After your 2 updates, the last logical update time will be 60, and you will then correctly update at t = 90.

And finally, remove the limiter from your render function. Renders are always, logical updates are sometimes.



In some physics heavy AAA titles, physics will actually be updated many more times per frame than a render or other update. This done gain a better approximation of the curves objects trace as they interact; Forza 3 I believe runs a physics update at 300hz, render at 60 hz to match the display refresh. There are many methods of maintaining numerical stability in a physics simulation; small time steps can help.

I do not believe this is accurate. There may be a few special-case objects or subsystems that update faster than the render, but the rule of thumb is to keep the major logical update (which also consumes the task of physics) as slow as possible without causing problems to your simulation.
Contrary to common belief, running physics at smaller time steps decreases the accuracy of the simulation, because every tiny calculation incurs some degree of floating-point imprecision, and these small errors are cumulative throughout the life of the simulation.
Not only will the physics be more accurate at around 30 milliseconds, it will cost less to the CPU and the game will run more smoothly.


Supreme Commander on the other hand only updates it's simulation at 10 hz. Changes to the state of the world, (unit orders, etc.) are actually only updated 10 times a second; units are updated once per frame to interpolate between simulation updates, so they appear to move smoothly through the environment. Supreme Commander does this to make it possible to synchronize the thousands of entities that can exist in a multiplayer game across the network; without the long intervals it would not be possible to keep all clients in sync. (and even then it can break down sometimes).

Again, this is not likely to be accurate. This update speed is typically too low for a stable physics implementation.
Some subsystems may run at this speed, such as the sound engine, but probably not physics.



L. Spiro

Share this post


Link to post
Share on other sites

[quote name='Yenian' timestamp='1323548808' post='4892611']
Supreme Commander on the other hand only updates it's simulation at 10 hz. Changes to the state of the world, (unit orders, etc.) are actually only updated 10 times a second; units are updated once per frame to interpolate between simulation updates, so they appear to move smoothly through the environment. Supreme Commander does this to make it possible to synchronize the thousands of entities that can exist in a multiplayer game across the network; without the long intervals it would not be possible to keep all clients in sync. (and even then it can break down sometimes).

Again, this is not likely to be accurate. This update speed is typically too low for a stable physics implementation.
Some subsystems may run at this speed, such as the sound engine, but probably not physics.
L. Spiro
[/quote]

Just to confirm L. Spiro's saying that 10 hz is definitely too low for physics simulation. The reason is mostly due to hard constraint objects in physics engines. One great example would be very stiff springs. They tends to explode. Since physics engine uses numerical approximation to simulate derivatives, or rate of changes, some simple math would easily show that the values increases exponentially. A simple tweak around this is instead of updating position with velocity, then velocity with acceleration, update velocity FIRST, then use this to update position during each integration. This however, puts a lower bound on frame rate. If the system have dt (1 over your frame rate) too big, then it would still explode. This is because any number that's less than 1 but greater than 0 raised to any positive power will yield a smaller result. Anything bigger than 1 raised to any positive non zero power will be bigger and thus explodes. Note that for details, please look for "Forward Euler" using Google.

CXD

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!