In game programming, nothing aggravates me more than God damn game loops. Working on a Pong clone, the issue struck me that I’m going to have a hard time updating a game running at 2000 or higher FPS. It’s simply impossible let stand for the player to keep up.
The game loop is a bit like your heart in that sense. It’s beating can be irregular, it depends changing on how much you need (much like FPS changing to how much the hardware can handle). If the heart was at a fixed rate, you’d have a pretty big issue and it’s the same with the game loop.
However, the serious problem that opposes with a variable frame rate is updating the game. This thread has been written mostly for myself, but hopefully, others can benefit of it too. This has been written with GLUT specifically in mind and to be API independent (Win32, etc).
The problem
The frame rate is extremely high or inconsistent (either is bad), and this seriously affects updating the game itself.
The solution
Update the game at a fixed amounts of times per second (I’ll go with 50) while the rendering and drawing happens at a variable rate. We’ll use interpolation to “guess” where objects are if the game updates and the frame rate aren’t similar (which they aren’t).
A note about GLUT and looping.
Glut uses many different kind of loops, a Display loop, an Idle loop and I know what not. Many game programmers I know prefer having a single loop for their game, called GameLoop(void) or whatever you want. This is actually done very simply.
int main(int argc, char** argv) {
// some code here...
glutDisplayFunc(GameLoop);
glutIdleFunc(GameLoop);
// some code here...
} /* End of main() *
There, now you got one, single game loop for the entire game. It’ll just do either whenever it likes, leaving you in control of what to do inside the actual loop. You would normally call for the draw function inside the Idle loop anyway. So no harm done there.
Now how to actually update the game at a fixed rate and the render at a variable rate? The answer is quite simple, actually. Normally you could use #defines and you would probably do the variables first, but for the sake of code clarity, I’m not going to bother with it. If you want to do game programming, you should probably get a hand for these kind of tricks anyway.
void GameLoop(void) {
/* We keep track of the amount of game loops we had. Reset it first. */
LoopsPassed = 0;
while ((glutGet(GLUT_ELAPSED_TIME) > NextTick) && (LoopsPassed < 5)) {
// ... your game update stuff goes here...
/* You can replace 50 here with the amount of times you want
to update the game, I personally prefer numbers that end on
a single number (no float: i.e 1, 50, 20, 100, 29). */
NextTick += ( 1000 / 50 );
LoopsPassed++;
}
/* The result of this number is what you need to guess where things
are at in the actual render part of your application. */
Interpolation = float(glutGet(GLUT_ELAPSED_TIME) + 5 - NextTick)
/ float(5);
// ... your rendering and stuff here ...
} /* End of GameLoop() */
On a different note, I’m by no means proud of the documentation of it’s code, but it should be mostly self explanatory. If not, well, feel free to ask me a question in a comment and I’ll clear it up (or try to).
A last thing regarding the game loop, you should think about the order of processing things. I personally do it like this for my pong clone:
- Input, I first check if the player actually pressed any keys. So I know I gotta do something with that first.
- Reposition (logical), with logical repositioning, I mean the X and Y coordinates for the objects in the game based on Input or not. Basically computing what’s going to happen. I also handle at what frame an animation is. This part also checks if the ball is bumping against the paddle, so it will move a different way.
- Artificial Intelligence, for the other paddle in single player.
- Reposition (logical), indeed. I now reposition things based on the computers act. This is okay because this is all done in the same loop.
- Prepare strings, like the frame rate string etc. Nothing fancy, mostly UI preparation and stuff.
- Reposition (physical), the drawing sequence stats here, this part is set at a variable rate. The physical reposition calculates where everything is and guesses object positions with the use of interpolation to fake the effect of the game updating at whatever frame rate we’re running. This will also make the game run ‘consistently’, ensuring there’s no difference between Player 1 and Player 2.
- Animation positions, camera angle, which are defined mostly in section 2 and 4 of the queue.
- Draw the scene. Nothing fancy. Then the loop returns to the begin.
Note that there’s actually a Zero in the loop, that’s the part that checks if the game loop should be run or not, the drawing loop is ALWAYS run.
And that’s it for today, I might expand this article later.
Cheers, Jesse.
