LEARN PYTHON | Project: A Complete Arcade Game

Lesson objective

Build an arcade game with title, play, pause and game-over states, time-based movement, spawning, scoring, damage rules and restart.

Learn

08.6 | PROJECT: A COMPLETE ARCADE GAME

01 | THE BRIEF: STAR RUNNER

Catch gold stars with a green player paddle and avoid pink rocks. A star gives ten points. The player starts with three lives and the round ends when lives reach zero or sixty seconds of simulation time pass.

Use Left/Right or A/D to move, Enter to start or restart, P to pause or resume, and Escape to quit. Window close must work in every state. The game has a title screen and final score rather than simply freezing after a loss.

The download contains all source and drawn assets. It needs Pygame, but no external artwork or audio files. It is a complete small learning game, not a commercial release or a networked multiplayer system.

Download Star Runner

02 | SET UP AND TRY THE FINISHED LOOP

Extract the project, create a fresh .venv and install its requirements with the selected interpreter. Run main.py to play. The pure model tests do not import Pygame, so they can run independently of graphics installation.

Learn the rules by playing before changing them. Catch a star, hit a rock, pause, resume, end a round and restart. Watch how the HUD displays score, lives and remaining simulation time.

The requirements file records the course’s Pygame range. For a tested machine snapshot, use the dependency workflow from Topic 7 rather than assuming one range describes every environment perfectly.

TERMINAL | PROJECT FOLDER

python -m pip install -r requirements.txt
python main.py
python -m unittest discover -s . -v

03 | MAP THE GAME STATES

A state is a meaningful operating mode. title waits for Enter, playing advances the world, paused draws the current world without advancing it, and over shows the final result and permits restart.

Transitions are controlled actions: Enter starts from title or over, P toggles only playing and paused, and a rule can move playing to over. Escape or QUIT exits independently of those transitions.

Do not create a new nested game loop for every screen. One loop continues processing events and drawing; its current state determines which rules are active.

Current stateAction / conditionResult
titleEnterReset round and play
playingPPause
pausedPResume same round
playingZero lives or time limitShow final score
overEnterFresh round
Any stateEscape or window closeExit cleanly

04 | GIVE THE FILES ONE JOB EACH

game_model.py owns dimensions, Falling records, collision checks and the Game rules. main.py owns Pygame input, the display loop and drawing. test_game.py supplies thirteen model tests.

The model contains float positions and simple records. It deliberately does not inherit pygame.sprite.Sprite: this keeps tests independent of the graphics library. The previous lesson showed how Sprite Groups work, while this project demonstrates explicit model/render separation.

Drawing should be able to run twice without changing lives or score. Updating should be testable without opening a display. These boundaries make bugs easier to locate.

ComponentResponsibility
Game.stepAdvance one bounded simulation step
Game.startReset every round-owned field
FallingStore one star or rock’s position, kind and speed
overlapsTest strict rectangle intersection
drawRender existing state without applying rules
mainEvents, held keys, clock, update and frame presentation

05 | MOVE, SPAWN AND REMOVE

The player moves at 340 pixels per second, bounded inside the 640-pixel screen. Falling objects appear at random legal x positions. Their speed and spawn interval gradually change with elapsed simulation time.

A spawn accumulator adds dt each step. When it reaches the chosen interval, subtract that interval and spawn. Retaining the leftover time avoids resetting the accumulator and losing its remainder.

Random(seed) can make a new model’s generated sequence reproducible in tests. Restart resets round state but continues that object’s random sequence; it does not promise exactly the same next wave every restart. Off-screen objects are removed to keep the active collection bounded.

06 | MAKE SCORING AND DAMAGE FAIR

For each falling object, update its position and test its box against the player. A star awards ten points and is consumed. A rock costs one life only when invulnerability is zero, then starts 0.8 seconds of protection.

Every overlapping item is removed, including rocks encountered during protection. Thus one star cannot score repeatedly and several rocks in the same step do not remove every life. These are explicit game-design choices, not automatic consequences of a collision library.

overlaps uses strict comparisons so touching edges alone is not a hit. The model tests boundary contact separately from real intersection. Fast motion can still tunnel between sampled positions; the capped step reduces but does not mathematically eliminate that limitation.

from game_model import overlaps

player = (100, 400, 48, 24)
print("Touching:", overlaps(player, (148, 400, 24, 24)))
print("One-pixel overlap:", overlaps(player, (147, 400, 24, 24)))

EXPECTED OUTPUT

Touching: False
One-pixel overlap: True

07 | PAUSE AND RESTART WITHOUT LEFTOVER STATE

Pause prevents model advancement: positions, spawn accumulator, remaining protection and simulation elapsed time stay still. The loop continues processing input and redrawing, so P and Escape still work.

start resets player position, active items, score, lives, elapsed time, spawn time and protection. Resetting only the score would leave hazards or damage from the earlier round.

The game caps dt at 0.05 seconds and counts a sixty-second simulation round. On a severely slow machine, those sixty simulated seconds can take longer than sixty wall-clock seconds. State that tradeoff instead of presenting the displayed timer as an exact real-time deadline.

08 | EXPLORE THE STATE MACHINE

Choose an action and watch which transitions are allowed. “Collect” and “Hit” are simplified fixed encounters for the illustration. The actual download uses moving objects and a protection timer.

State: title
Score: 0
Lives: 3

09 | TEST THE RULES AND THE PLAY EXPERIENCE

The thirteen model tests cover movement, bounds, one-time collection, protection, pause, zero-life and time-limit endings, spawning, off-screen removal, seeded repeatability, collision edges and invalid-update rejection.

A direct model check can inject a stationary star overlapping the player and advance zero seconds. This isolates the collision outcome without relying on keyboard skill or a lucky random wave. The sample belongs beside game_model.py.

Manual play tests also matter: input focus, both directions held, visible instructions, readable HUD, closing from every screen and a restart with clean state. Automated arithmetic checks cannot decide whether the challenge feels enjoyable.

from game_model import Game, Falling

game = Game(seed=7)
game.start()
game.items.append(Falling(game.player_x, game.player_y, "star", 0))
game.step(0, 0)
print("Score:", game.score)
print("Items left:", len(game.items))
game.toggle_pause()
before = game.elapsed
game.step(0.02, 1)
print("Pause froze time:", game.elapsed == before)

EXPECTED OUTPUT

Score: 10
Items left: 0
Pause froze time: True

10 | FINISH, DOCUMENT AND CHOOSE ONE EXTENSION

Include install commands, controls, rule summary and test commands in the handover. The score is session-only; the project does not store a high score between launches. Use no external assets without checking their use conditions.

Useful extensions include a saved high score, sound feedback, a settings screen or a difficulty choice. A saved score needs careful file validation; difficulty needs clear values and tests; audio should not be essential to understanding the game.

Change one feature at a time and keep a tested Git commit before experimenting. Ask another student to play without verbal coaching, then improve one confusing instruction or unfair rule based on their evidence.

OFFICIAL REFERENCE

Use the worked examples first, then consult the official documentation to check widget, input or drawing options. Match it to the version selected in your project environment.

PUT YOUR SKILLS TO WORK

Use the Section 8 challenges to practise these ideas independently. Work in your Python editor, predict results and keep a short test record.

Section 8 challenges Python course navigation

MATCH THE PYTHON TERM TO ITS MEANING

Terminology

Terminology

State machine

Modes and controlled transitions determining application behaviour.

Title state

The initial screen waiting for a start action.

Playing state

The mode in which simulation updates advance.

Paused state

A mode drawing the world without advancing its rules.

Game-over state

The mode presenting a finished round and restart option.

HUD

The heads-up display showing useful play information.

Spawn

Create an active game object.

Accumulator

A stored amount of elapsed time carried between updates.

Seed

A starting value making a pseudo-random sequence repeatable.

Round state

The data that must be reset for a new round.

Simulation time

Time accumulated through game update durations.

Wall-clock time

The real elapsed time outside the simulation’s update policy.

Damage cooldown

A temporary rule preventing repeated immediate damage.

Renderer

Code drawing current state without deciding the game rules.

Pure model

Rules that do not depend on opening a graphics interface.

Injected encounter

A controlled object placement used to test a collision outcome.

Session-only score

A score retained only during the current process.

Playtest

A test of the game’s usability and experience through actual play.

Questions

Questions

CHECK YOUR UNDERSTANDING

Select all correct choices. Each exact set earns one point.

1. Which states accept Enter to begin a fresh round?
2. Which data should restart reset?
3. How much does one consumed star award?
4. What does the damage protection rule do?
5. What freezes during pause?
6. Why use a seeded model in a test?
7. What does the sixty-second capstone timer measure?
8. Why keep rules independent of Pygame drawing?

EXPLAIN AND COMPARE

Write your answers before revealing each sample.

1. Explain the state-machine approach.

2. Describe a consumed star encounter.

3. Explain the protection rule.

4. Explain pause without freezing input.

5. Describe a complete restart.

6. Compare simulation and wall-clock time.

7. Describe a deterministic collision test.

8. Evaluate one finished-game limitation.

CODE IT | YOUR INDEPENDENT CHALLENGE

Complete the arcade game and test scoring, protection, pause, endings and clean restart.

Work in your Python editor. Keep a working version, explain one design choice and record at least two tests. Use the Learn tab for worked examples before comparing your result.

Flashcards

Flashcards

Click to flip. Select the ideas you need to revisit.

0 cards selected for revision.

    Selections are kept while this page is open.

    Workbook

    Workbook

    COMING SOON

    The workbook for Project: A Complete Arcade Game is coming soon. Complete the matching task and written questions in your exercise book.