Higher-Order Fun

Game Design & Game Programming

Understanding the Game Main Loop

Video games are simply ordinary software – there’s nothing intrinsically special about them. However, they SEEM to behave in a very different way from your ordinary everyday applications – so much that many experienced programmers are at a complete loss when faced with the task of developing a game from scratch. This difference is mostly caused by game’s close ties to their main loop. In this article, we’ll examine what is the main loop, how it works, and why it’s important.

A simple model

How simply could we model a computer game? Let’s start by separating the game in two parts: the data inside the computer, and everything outside the computer. This might seem like a strange thing to say, but remember that games are, first and foremost, interactive software. So, outside the computer, we have (at the very least) the player. Inside the computer we have all sorts of data, but the most important is what we call the game state: it contains all the dynamic information of the game: the position of the player, monsters and camera; the current time; the score – in essence, everything that changes with time.

A computer game can then be understood as a system in which those two entities – player and game state – interact with each other according to a specific pattern of rules. The player inputs data into the system, and the system uses the game state to generate output to display to the player. This is not very different from ordinary applications, in which e.g. a click (input) might cause a dialog to show up (output). The difference is how that behaves in respect with time.

The Game Loop

Most applications are developed in a reactive way – your program just sits around waiting for the user to click something, and then it does something in response. There is a main loop behind your application as well, but it’s not important – it’s abstracted away. With games, your code is constantly being invoked, even in the absence of user input.

The pseudo-code for a video game will often look like this:

void GameClass::main() {
    init();
    runMainLoop();
    deInit();
}

The main loop looks something like this:

while (running) {
    processInput();
    updateGameState();
    drawScreen();
}

First, it reads input from the user and stores it somewhere. Here, it will check the keyboard, gamepad, plastic guitar and network message queues – basically, it will collect all information from the outside world.

After that, it will use that information to update the game state – depending on what conditions we have, they will have different results. For example, on the menu screen, detecting that the “down” arrow got pressed might increment the “currently selected menu item” variable, but the same input while on the game might instead trigger the “set player as moving down” flag. Note that the world update is invoked even if the user didn’t perform any input. This is a very important property of most video games.

Lastly, it will collect the current game state data to generate the output – it will figure out where the player and camera and everything else are, and generate an image to display on the screen. A more complicated game will also have to deal with other forms of output – audio and network, for example.

A More Sophisticated Main Loop

The loop pseudo-code above suffers from a major flaw: it will run at unpredictable speeds – on fast machines it might run thousands of times per second (which would be a waste), and on slow machines it might run on unacceptably slow speeds – perhaps only five updates per second or so. Besides the obvious issues, this makes the game much harder to program – it’s much easier to write your game logic when you know that you’ll have a fixed number of steps per second.

Consider this: the player presses the right arrow, and you store a flag containing that information. Now, on every step, regardless of any player action, you’ll move the player to the right by 1 unit in the game state (which, let’s say, corresponds to 1 pixel on the screen). If the game runs at 5 Hz (that is, 5 updates per second), the player will move VERY slowly. If it runs at 5000 Hz, he’ll be out of the screen before you can even see it!

A possible solution to this is to calculate the real time elapsed between two steps and use this information during the step. In practice, however, this makes the game development much harder and error prone. It will also make networking a true nightmare, and will essentially make reliable behavior (e.g. replays) impossible.

A much better solution is to fix the rate at which your game performs its updates. Most modern games use an internal clock of 60 Hz or 30 Hz. Let’s assume 60 Hz for our example. This means that, 60 times per second, your game will check the input from the player, update the game state, and try to display something on the screen. But how do we control that?

First, let’s consider the case of a very fast computer. In this case, before each iteration of the main loop, we’ll check if it’s time for the update. If it isn’t, we’ll simply wait (preferably yielding the time slice back to the operating system), without doing any processing.

In the case of a slower computer, things are trickier – we can’t skip on updating the game state, or the game will run in slow motion, so we must sacrifice the output – the screen rendering. On most games, screen rendering is the slowest part of the pipeline, meaning that most games WILL be able to run at 60 Hz given enough sacrifice on graphics. If not, then the game will be way too slow, and we have no choice but ask the player to get a better computer.

In pseudo-code, our new algorithm now looks somewhat like this:

while (running) {
    if (isTimeToUpdate()) {
        processInput();
        updateGameState();
        if (hasTimeToDraw()) drawScreen();
    } else {
        waitUntilItsTime();
    }
}

It’s simple, but it’s very similar to real game loops found in real games.

The Foundation

At this point, it should be clear that the vast majority of the game code will run inside the main loop – in a simple game, everything except for initialization and deinitialization. Also, that code is now separated in three functions: processing input, updating the game state, and rendering the screen. Since all three of them are controlled by the loop, it’s the foundation block of every game.

Having this foundation, your task of implementing a game has been reduced into three simpler and relatively independent tasks. The input you collect will be used on the state updating stage, and the state created by that step will be used to generate the output to the user, but they are each their own logically distinct operations, and how they interact with each other is now clear.

If you understand the topic discussed in this article, then all you have to figure out in order to make a (very) simple game is “how to read user input?”, “how to draw stuff on the screen?” and “how to keep track of my state and update it?”. None of those are, at a basic level, difficult, but they might be different from what programmers are used to coding.

On the next article, we’ll try to figure those things out and write an extremely simple real-time game using those concepts.

9 ResponsesLeave one →

  1. This is… pretty good. I mean, I love the way you explain things, with much more detail than the usual “hey it’s the main loop you check things in it”, and yet, with so much clarity that the reader can understand everything… pretty good stuff. Now, go ahead and write the follow-up :)

    (and who am I to talk? My blog hasn’t seen an update in months…)

  2. Dan

     /  2010-10-01

    Where is the next article?

  3. Awesome article!
    I was looking for a simple introduction to game loops and your pseudo-code helped me a lot!
    I’m currently programming simple games for fun (and to learn) and the time solution you gave was very helpful.
    You write so well! Thanks for writing this!

  4. GaameProgrammer

     /  2012-08-14

    Hey thanks I liked the way you write and explain things … I read platformer post also …and that was also amazing .. I wish you can write on post on grid base games to make us understand like the way you explain …
    Thanks mate i am following your blog!!!

  5. joe

     /  2012-11-23

    I’m waiting the next article
    :D

  6. asdf

     /  2013-07-01

    kjfoaslk foslk jtoslkj foalkjdf

  1. game loop « tediscript.wordpress.com
  2. Link: Higher-Order Fun | Keith M. Programming
  3. Side Quests #1 | Chocollision

Leave a Reply

*