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:
- Explain why a game program must keep running instead of executing once and exiting
- Split a program’s per-frame work into separate processInput, update, and render responsibilities
- Drive those three calls from a while loop guarded by a boolean exit flag
- Count and report how many times the loop actually ran
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.
- In
processInput(), print a line describing that input is being processed. - In
update(), print a line describing that game state is being updated. - 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.
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.
- Declare a file-scope
bool gameOver = false;abovemain. - Inside
processInput(), keep astatic int callCount, increment it each call, and setgameOver = trueonce it reaches10. - In
main, write awhile (!gameOver)loop that callsprocessInput(), thenupdate(), thenrender(), 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.
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.
- In
main, declare anint frameCount = 0;before the loop. - Increment
frameCountonce per pass through the loop, afterrender()has run. - After the loop ends, print
frameCountto the console.
Success condition: the program now prints a final line such as Loop ran 10 times. after the three-message sequence stops repeating.
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.