University of Wales Trinity Saint David
ACCB5017 - Games Architecture and Mechanics

Basic Game Loop

Overview

This lab builds the smallest possible game loop: a program that keeps processing input, updating state, and rendering for as long as it runs, instead of executing once and exiting. Starting from three stub functions, you will wire them into a single while loop guarded by an exit flag, and finish with a count of how many times the loop actually ran. No timing is involved anywhere in this lab. The loop's shape, not its speed, is the whole point.

Learning Objectives

By the end of this lab you will be able to:

Concept

A typical console program runs its instructions once, from top to bottom, and then exits. A game cannot behave this way. It has to keep responding to input and drawing frames for as long as it is being played, and nobody knows in advance how long that will be. The program needs a way to keep doing the same handful of things, over and over, until something tells it to stop.

The game loop is that mechanism. Every interactive program repeats the same three responsibilities on each pass: read whatever input has happened, advance the game's state, and draw the current result. A game loop wraps those three calls inside a loop that keeps running as long as a boolean flag says it should. Each pass through the loop is often called a frame or a tick. Something inside the loop, usually the input-handling step, is what eventually flips that flag and lets the loop end.

The pieces involved are a plain C++ while loop, three free functions (processInput, update, and render) standing in for the three responsibilities, and a bool variable such as gameOver that the loop condition checks on every pass.

Tasks

Task 1 - Stubbing the three responsibilities

Open BasicGameLoop.cpp and find the three stub functions above main. Each one stands in for one responsibility a game repeats every frame. For now they only need to announce that they ran.

  1. In processInput(), print a line describing that input is being processed.
  2. In update(), print a line describing that game state is being updated.
  3. In render(), print a line describing that a frame is being rendered.

Success condition: calling all three functions once each, for example from the top of main, prints three distinct lines to the console.

BasicGameLoop.cpp
void processInput()
{
    // TODO: print a line describing that input is being processed
}

void update()
{
    // TODO: print a line describing that game state is being updated
}

void render()
{
    // TODO: print a line describing that a frame is being rendered
}

Task 2 - Driving the loop with an exit flag

In main, wire the three stub functions into a loop that keeps calling them until something ends it. There is no real input device yet, so processInput() will simulate one: it counts how many times it has been called and sets a shared gameOver flag once that count reaches a fixed limit, standing in for the moment a player would quit.

  1. Declare a file-scope bool gameOver = false; above main.
  2. Inside processInput(), keep a static int callCount, increment it each call, and set gameOver = true once it reaches 10.
  3. In main, write a while (!gameOver) loop that calls processInput(), then update(), then render(), in that order, on every pass.

Success condition: running the program prints the three messages from Task 1 repeatedly and then stops on its own after 10 passes, instead of running forever.

BasicGameLoop.cpp
bool gameOver = false;

void processInput()
{
    // TODO: keep a static callCount, increment it, and set gameOver = true
    // once callCount reaches 10

    std::cout << "Processing input..." << std::endl;
}

// ... update() and render() unchanged from Task 1

int main()
{
    // TODO: write a while (!gameOver) loop that calls processInput(),
    // update(), and render() on every pass
}

Task 3 - Counting and reporting how many times the loop ran

Right now the loop stops after 10 passes but never says so. Add a counter that main owns itself, separate from processInput's internal callCount, so the program can report exactly how many full passes it completed.

  1. In main, declare an int frameCount = 0; before the loop.
  2. Increment frameCount once per pass through the loop, after render() has run.
  3. After the loop ends, print frameCount to the console.

Success condition: the program now prints a final line such as Loop ran 10 times. after the three-message sequence stops repeating.

BasicGameLoop.cpp
int main()
{
    int frameCount = 0;

    while (!gameOver)
    {
        processInput();
        update();
        render();
        // TODO: increment frameCount
    }

    // TODO: print frameCount to std::cout

    return 0;
}

The diagram below traces one full pass through the loop once all three tasks are wired together, from processInput() through to the check that either loops back or ends the program.

Solution

Try the tasks above before revealing the solution.