This tutorial will cover one of the most basic components of a game, the game loop. The game loop is what actual drives your game. It manages the calls to your logic and drawing functions. While doing this, it performs the vital role of maintaining a consistent game speed (also called a logic rate). Creating a game loop is not always an easy thing. Many newer programmers get stuck on this. This tutorial will explain what a game loop is, how to create one, and what are some common pitfalls.
A Simple (and Flawed) Game Loop
First, what is a game loop? At its most basic a game loop is a state machine. For a game there are usually four main states.
- Start: This is where the program performs any initialization.
- Stop: Here, any open resources should be released.
- Update: Here is your game logic.
- Draw: This is where all the drawing goes.
The simplest game loop may consist of these four states. Start is called first, performing any initialization then the main game loop is entered. Update and draw are called repeatedly until the program exits to the stop state. Figure 1 shows a diagram of this simple game loop.

Figure 1: A simple game loop.
A game loop like this is as easy to implement as it is to draw.
public abstract class GameLoop
{
private boolean runFlag = false;
public void run()
{
runFlag = true;
startup();
while(runFlag)
{
update();
draw();
}
shutdown();
}
public void stop()
{
runFlag = false;
}
public abstract void startup();
public abstract void shutdown();
public abstract void update();
public abstract void draw();
}
This method has a significant problem. Because the game loops as fast as possible, update will be called much more frequently on a fast computer than a slow one. This means that the game will run at different speeds for different users, something that you definitely don’t want.
A Frame Rate Limited Game Loop
There are several options at this point. The first would be making the update aware of how much time the loop took. For example, if the loop takes half as long as expected, only move the objects half as far. Unless you are very careful, this can cause problems particularly when updates are very fast or slow. This also makes the behavior of the game much less repeatable.
Another option would be to repeat the drawing step until it is time to update again. This would work, but it is not necessary and could in fact be harmful. If the game is not being updated then the drawing probably is not changing either. The harm can come from overworking the graphics card. Starcraft 2 had this problem when it was released, because the frame rate was not capped in menu screens.
What we will do is put the program to sleep if we finish the loop early. Figure 2 shows the new state diagram. Sleeping has a few additional benefits. If our game is multi-threaded, this gives other parts of the code time to execute. It also behaves better with the other processes on the computer (or other system).

Figure 2: A frame rate limited game loop.
Here is the code for the frame rate limited game loop.
public abstract class GameLoop
{
private boolean runFlag = false;
/**
* Begin the game loop
* @param delta time between logic updates (in seconds)
*/
public void run(double delta)
{
runFlag = true;
startup();
// convert the time to seconds
double nextTime = (double)System.nanoTime() / 1000000000.0;
while(runFlag)
{
// convert the time to seconds
double currTime = (double)System.nanoTime() / 1000000000.0;
if(currTime >= nextTime)
{
// assign the time for the next update
nextTime += delta;
update();
draw();
}
else
{
// calculate the time to sleep
int sleepTime = (int)(1000.0 * (nextTime - currTime));
// sanity check
if(sleepTime > 0)
{
// sleep until the next update
try
{
Thread.sleep(sleepTime);
}
catch(InterruptedException e)
{
// do nothing
}
}
}
}
shutdown();
}
public void stop()
{
runFlag = false;
}
public abstract void startup();
public abstract void shutdown();
public abstract void update();
public abstract void draw();
}
There are a few subtleties to notice in the code. First, we now have an additional parameter called delta. This is the amount of time between each logic (and drawing) update. When we update nextTime, delta is added to it. What we don’t want to do is get the time again and add delta to it. That may result in lost pieces of time, particularly if the update is late. Second, every loop either updates and draws OR sleeps. If this was not the case, we would need to re-sample the time because it would be outdated by the time we reached the sleep section.
An Advanced Game Loop
We are not done improving our game loop yet. So far we have draw being called every time update is. What if our program is running slow? It may be a good idea to skip some of the calls to draw so that we continue to update at the correct rate. We can now update our state diagram to figure 3.

Figure 3: An advanced game loop.
We only need to change one line of the code to implement this change.
draw();
becomes…
if(currTime < nextTime) draw();
A More Advanced Game Loop
The game loop so far should work just fine in most situations, but what if the updates get significantly behind? Currently, the game loop would try to run as many updates as necessary to catch up. This may cause the game to skip a significant amount ahead, a major problem if players are expected to react quickly to events. What we need to do is allow the nextTime to skip ahead if we have fallen to far behind.
Another potential problem when the game is running slow is that draw will never get called. This can be fixed by forcing the game to be drawn every so often. Both of these changes have the consequence that the game may no longer run at the correct rate is the updates and draws are taking to long. Whether or not this is acceptable depends on the game, but keeping the game responsive is often more important. If you do not want that functionality, just don’t include the last two changes. Figure 4 shows the final state diagram.

Figure 4: A more advanced game loop.
Here is the final source code:
public abstract class GameLoop
{
private boolean runFlag = false;
/**
* Begin the game loop
* @param delta time between logic updates (in seconds)
*/
public void run(double delta)
{
runFlag = true;
startup();
// convert the time to seconds
double nextTime = (double)System.nanoTime() / 1000000000.0;
double maxTimeDiff = 0.5;
int skippedFrames = 1;
int maxSkippedFrames = 5;
while(runFlag)
{
// convert the time to seconds
double currTime = (double)System.nanoTime() / 1000000000.0;
if((currTime - nextTime) > maxTimeDiff) nextTime = currTime;
if(currTime >= nextTime)
{
// assign the time for the next update
nextTime += delta;
update();
if((currTime < nextTime) || (skippedFrames > maxSkippedFrames))
{
draw();
skippedFrames = 1;
}
else
{
skippedFrames++;
}
}
else
{
// calculate the time to sleep
int sleepTime = (int)(1000.0 * (nextTime - currTime));
// sanity check
if(sleepTime > 0)
{
// sleep until the next update
try
{
Thread.sleep(sleepTime);
}
catch(InterruptedException e)
{
// do nothing
}
}
}
}
shutdown();
}
public void stop()
{
runFlag = false;
}
public abstract void startup();
public abstract void shutdown();
public abstract void update();
public abstract void draw();
}
-Eric

Pingback: How can I tell OpenGL how often to draw stuff? - Programmers Goodies
Pingback: Event Driven Programming: A sequence of unfortunate events | Question and Answer