Skip to content
Lesson 1.2Computer, Game, and Code Foundations

How a Computer Runs a Game

Build a game from CPU instructions, a small program, stored values, and the services that make it interactive.

Lesson 1.2
Read or listenPrint chapter or book
About 16 minutes

Keyboard shortcuts

?
Open this guide
Alt + B
Show or hide the lesson list
Alt + O
Show or fold the lesson outline
Alt + N
Open or close notes
Alt + H
Toggle semantic colours
Alt + D
Toggle page brightness
Alt + C
Toggle code brightness
← →
Move through a focused code trace
Home End
First or final step in a focused trace
Escape
Close this guide or an open panel

Reader shortcuts pause while you type in a text field.

Cheatsheet for Lesson 1.2Key ideas, reference and questions

A one-page summary of “How a Computer Runs a Game” you can keep beside your notes. Plain Markdown.

Lesson 1.2 — How a Computer Runs a Game: cheatsheet

  • Remember: The CPU only does tiny steps such as copy, add and compare. Everything a game does is built from those.
  • Also useful: Changing gold in a working register or memory does not save the game. Persistent output needs a separate save operation.

Key terms

  • registers: The CPU has tiny working places called registers.
  • cache: A cache holds memory lines the processor may reuse; it is not another set of variables the game names.
  • input: The input is the value supplied to this calculation.
  • result: The name number stands for the input supplied on each use; result is the value after adding one.
  • number: number is its input; u32 means a non-negative whole number stored in 32 bits.
  • application: An application is a program made for a user to do something.

Formulas and patterns

  • function add_one(number):; result = number + 1; give back result; add_one(100) gives back 101

Review

  • Q: The input is 100 and the action is spend. In the lesson's add-or-subtract example, which result does the branch choose? A: 99, because the branch follows the subtract_one path for spend
  • Q: While a game runs, which part holds the current gold value? A: RAM, the fast working storage for the running program's values
Download cheatsheet (.md)

Suppose a game shows 100 gold. You collect one coin, and the display changes to 101. What had to happen inside the computer for that small change to appear? We can answer without knowing a programming language yet.

The game’s files stay on a storage drive when the game is closed. When you start it, the computer puts the code and the information needed soon into RAM (random-access memory). RAM is fast working storage; its contents are temporary. The CPU (central processing unit) runs the code and changes values such as your gold. A keyboard, mouse, or controller supplies input. The GPU (graphics processing unit) helps turn the game’s drawing work into the picture you see.

These parts have different jobs in our coin example. The stored game file contains the instructions for collecting a coin. While the game runs, RAM holds the current gold value. The CPU updates that value from 100 to 101, and the game draws the new number on the screen. The parts communicate through the computer’s hardware; none of them is the whole game by itself.

Changing gold and drawing it are separate workThe CPU changes the stored value first. The screen shows 101 only after a separate drawing step reads it.
  1. 1 Before: RAM and the screen both say 100

    idleCPU register
    100RAM: gold
    Gold: 100screen

    The stored gold and the picture agree.

  2. 2 Update: the CPU adds 1 and stores 101

    100 + 1 = 101CPU register
    101RAM: gold
    Gold: 100screen: old picture

    RAM now holds 101, but nothing has drawn a new picture yet, so the screen still shows 100.

  3. 3 Draw: the next picture reads 101

    reads 101drawing step
    101RAM: gold
    Gold: 101screen

    The drawing step reads gold from RAM and builds a new picture. Now the screen agrees with RAM.

The CPU changes the stored value first. The screen shows 101 only after a separate drawing step reads it.

game files on storage
code and current values in RAM
CPU runs instructions
keyboard or controller input
updated gold in RAM
GPU helps draw the picture
screen

The CPU is sometimes called the computer’s brain. That is a useful first picture of its central job, but the CPU does not understand a game as a person does. It executes instructions: small, specified operations such as copying a number, adding two numbers, comparing them, or going to another instruction.

The CPU has tiny working places called registers. Imagine one register currently holds 100. An add-one instruction changes that register’s value to 101. It did one small job; it did not decide what a coin means or draw the number. Later, the program can store the result in RAM for continued use.

This is a description of the change, not executable CPU code:

working value starts at 100
add 1 to the working value
working value is now 101

The exact CPU instructions and register names depend on the machine. For now, follow the value: 100 went in, one was added, and 101 came out.

A register change reaches memory and the display. This step-by-step trace needs JavaScript. Here is the code and where the run ends.

RAM.gold = starting_gold
working = RAM.gold
working = working + 1
RAM.gold = working
display = RAM.gold
draw the copied display value

Result: memory and the new display both contain 101; they changed at different steps.

Final values: gold = 100; stored_gold = 101; working = 101; display = 101.

Read every step of the lesson’s example
  1. Step 1, line 1. Start with the selected inputs. Follow the highlighted operation and the changing state below.

    gold = 100.

  2. Step 2, line 1. RAM and the last drawn display start at 100.

    gold = 100; stored_gold = 100; working = not loaded; display = 100.

    Memory: RAM.gold = 100; working = not loaded; display = 100.

  3. Step 3, line 2. Copy the stored amount into a working register.

    gold = 100; stored_gold = 100; working = 100; display = 100.

    Memory: RAM.gold = 100; working = 100; display = 100.

  4. Step 4, line 3. Add one to the temporary value. RAM still contains 100.

    gold = 100; stored_gold = 100; working = 101; display = 100.

    Memory: RAM.gold = 100; working = 101; display = 100.

  5. Step 5, line 4. Store the result. Future calculations can now read the new amount.

    gold = 100; stored_gold = 101; working = 101; display = 100.

    Memory: RAM.gold = 101; working = 101; display = 100.

  6. Step 6, line 5. Copy the stored amount for drawing.

    gold = 100; stored_gold = 101; working = 101; display = 101.

    Memory: RAM.gold = 101; working = 101; display = 101.

  7. Step 7, line 6. Result: memory and the new display both contain 101; they changed at different steps.

    gold = 100; stored_gold = 101; working = 101; display = 101.

    Memory: RAM.gold = 101; working = 101; display = 101.

Working values live at different distances from the CPU

Section titled “Working values live at different distances from the CPU”

A register holds a value named by an instruction. A cache holds memory lines the processor may reuse; it is not another set of variables the game names. Common CPUs have L1, L2, and L3 cache levels. A cache hit can serve a memory request nearby; a miss may require a farther cache level or RAM. Intel’s cache explanation describes why those extra fetches can make the CPU wait.

RAM holds the running program’s resident code and data. An SSD or HDD keeps persistent files; the operating system performs file I/O to bring their contents into working memory. Their capacities and access times depend on the machine, so this hierarchy gives roles rather than fixed speed numbers.

Working values and saved filesWorking storage above · persistent storage below
  1. CPU registersValues named directly by instructionsSmallest working set
  2. CPU caches · L1 / L2 / L3Copies of memory lines near the CPUA hit avoids a slower fetch
  3. Main memory · RAMResident program code and dataA larger working set
Explicit file I/O or OS pagingStorage access is a separate operation
SSDPersistent files in flash storage
HDDPersistent files on magnetic disks

A cache miss can require a RAM fetch; it does not automatically mean a disk read. Capacity and timing depend on the machine.

A program is a collection of instructions arranged to do a larger job. Our example becomes a tiny program if we let a number come in and send the new number out:

input: 100
copy the input into a working value
add 1 to the working value
output: 101

The input is the value supplied to this calculation. The output is its result. A running program can also remember values, cause effects, and keep working rather than stop after one output. In a game, the gold count is part of the game’s changing state: information describing what is happening now. The input might be the event “collect a coin,” and the new state has 101 gold.

A larger program may need to add one in many places. We can give that small behavior a name: add_one. A named piece of program behavior is a function. Instead of describing its steps every time, another part of the program can ask add_one to work on a number.

function add_one(number):
result = number + 1
give back result
add_one(100) gives back 101

This is explanatory pseudocode, not code you can run as written. The name number stands for the input supplied on each use; result is the value after adding one. A function can also do work without taking an input or returning a useful value. Naming behavior lets the program reuse and organize it.

What if a game can award a coin or charge one? We can name the second operation subtract_one. Both operations change the same starting number by one. Now the program needs another input: which action occurred?

starting number: 100
action "collect": add_one(100) gives back 101
action "spend": subtract_one(100) gives back 99

For “collect,” the program follows the add path and ends at 101. For “spend,” it follows the subtract path and ends at 99. It must compare the action with the choices and then follow one path. This choice is a branch. A branch lets the same program respond differently to different input. It does not run both outcomes for one action.

collect
spend
starting number: 100
which action?
add_one gives 101
subtract_one gives 99

In a real game, spending may also need a rule such as “do not spend when gold is zero.” That is another comparison and branch. Lesson 1.4 will turn this small calculation into a program written in Rust.

We have treated 100 and 101 as ordinary numbers. To find them in a running game, we also need to know how computers represent numbers.

In familiar decimal notation, each place is worth ten times the place to its right. The number 101 means one hundred, zero tens, and one unit: 1 × 100 + 0 × 10 + 1. Binary uses only 0 and 1. Each place is worth twice the place to its right. One binary digit, either 0 or 1, is a bit.

Eight bits make one byte. The eight places in a byte are worth 128, 64, 32, 16, 8, 4, 2, and 1. For example:

place value: 128 64 32 16 8 4 2 1
bits: 0 1 1 0 0 1 0 0
total: 64 + 32 + 4 = 100

Writing eight bits for every byte gets tiring. Hexadecimal, or hex, uses sixteen digits: 0–9 followed by A–F for values ten through fifteen. One hex digit represents four bits, so two hex digits represent one byte. The byte above splits into 0110 (six) and 0100 (four), written 0x64. The prefix 0x tells you it is hex. Its value is still decimal 100: 6 × 16 + 4. Decimal, binary, and hex are different ways to write the same number, not three different kinds of gold.

high four bits0110
low four bits0100
hex 6
hex 4
0x64 = 6 × 16 + 4 = 100
The same one-byte value, split into two groups of four bits and written in hexadecimal.

One byte can represent 0 through 255. Larger values use several bytes. The memory lesson just before the first scan will show where those bytes sit and how a program reads them together.

The CPU executes instructions represented by patterns of bits. Writing a whole game as bit patterns would be difficult. Assembly language gives human-readable names to operations such as moving and adding values. A higher-level language lets us express larger ideas, such as functions and branches, without spelling out every CPU operation.

Our add-one function and collect-or-spend branch can be written in a language like Rust. A compiler translates source code into machine code for a chosen target. The translation is not necessarily one source line to one CPU instruction. Here is our same small function in Rust:

fn add_one(number: u32) -> u32 {
return number + 1;
}

fn names a function. number is its input; u32 means a non-negative whole number stored in 32 bits. The arrow says the function gives back a u32, and return sends back the sum. Calling add_one(100) therefore gives back 101, just as the earlier pseudocode did. This is a function fragment, not a whole program; Lesson 1.4 builds and runs the complete Rust example. Lesson 2.2 follows the later steps that turn source into a program file.

The operating system helps programs use the computer

Section titled “The operating system helps programs use the computer”

Even our tiny add-one program needs more than arithmetic if a person must type a number and see an answer. It needs a way to receive input and display output. A game also needs files, sound, windows, and access to devices.

An operating system (OS) provides common services for those jobs and coordinates programs that use the computer. This book uses Windows for its practical examples. A program written for Windows can ask Windows to read a file or show a window instead of controlling each device from scratch.

An application is a program made for a user to do something. A game is an application: it uses the OS’s services, runs its own instructions, and keeps its own changing state.

The Rust source a developer writes has already been translated into machine instructions and linked with other code before the native game file exists. Other games may load scripts that an interpreter runs while the game is open. Either way, the CPU eventually carries out instructions. Lesson 2.2 follows those routes in detail; here we start with the native game file.

The game file on storage contains code and other saved information. Starting it creates a process: one running instance of that program, with its own memory and resources. Windows loads the code and needed data into memory and starts a thread, a path that executes instructions in the process. A process may have more than one thread, but one is enough to picture this first example.

Many games repeat a broad game loop while you play:

  1. receive input, such as the event “collect a coin”;
  2. update state, changing gold from 100 to 101;
  3. draw the current state, so the display shows 101;
  4. repeat for the next action.
input: collect a coin
CPU follows the game's instructions
state in RAM: gold is 101
draw 101 on screen
next input

Actual games split this work among many systems and sometimes several threads. This loop is a first model for asking a useful question: did the input arrive, did the stored value change, and did the display show the changed value?

The CPU carries out individual instructions. A program arranges many of them into useful behavior: receive a value, apply the add-one operation, and produce a changed value. A function names that reusable behavior; a branch chooses whether to collect or spend. Storage keeps the game file, RAM holds the running program’s state, and the operating system loads the file as a process the CPU can execute.

The gold value changed while the game was running. The next question is what the game’s rules do with it and how several players can each have their own value. Game Fundamentals starts there. We will return to bytes and addresses just before the first memory scan in Lesson 1.8.

Knowledge check

Follow one choice

The input is 100 and the action is spend. In the lesson's add-or-subtract example, which result does the branch choose?

Finished Lesson 1.2?

Mark it done and the lesson list shows a beside it. A chapter whose lessons are all done is marked done too. Progress is saved in this browser only.

Chapter 1: 10 lessons

This book grew out of the original Game Hacking Academy by attilathedud and has been rewritten as a beginner-first course. Like the original repository, its source is published under the Apache License 2.0.