SeeThinkExploreMarvel

UMPSA STEM LAB · Step 2 of 10

Step 2 — Loop & Events

Build the heartbeat of every game: a loop that runs 8 times per second — listening for input, drawing the screen, and keeping perfect time.

while loopBooleanEvents Clock / FPSIteration
Step 2 / 10

What you'll build in Step 2

You'll upgrade Step 1's 3-second window into a proper game window that stays open until the player closes it — and runs at a steady 8 frames per second.

🎯 Learning goals

Understand while loops, Boolean values, the event queue, and how a clock controls game speed.

🐍 Snake game progress

This game loop is the skeleton every later step builds on. Steps 3–9 only add code inside this loop — the structure never changes.

Computational Thinking (CT) skills this step

🔍 Decomposition 🔄 Pattern Recognition 💡 Abstraction 📋 Algorithm Design

Each badge below shows where each CT skill appears in this step.

CT: Decomposition — breaking the game into steps

Every game — Snake, Minecraft, any mobile app — has the same three-part cycle. Recognising this pattern is Decomposition at work.

🔍 Decomposition

Breaking a complex problem (run a game) into smaller, repeatable sub-problems (handle input → update state → draw screen).

The universal game loop

① Handle
Events
→
② Update
Game State
→
③ Draw
Screen
→
④ Tick
Clock
↺ repeat

This pattern appears in every real-time game ever made. You are learning the industry standard, not a classroom abstraction.

① Events (Step 2)

Read keyboard, mouse, window-close events every frame.

② Update (Steps 3–7)

Move snake, check collisions, grow body, update score.

③ Draw (Step 4+)

Fill background, draw snake segments, food, score text.

④ Clock (Step 2)

Wait so the loop always runs at the same speed.

The while Loop — how it works

A while loop checks a condition. If it is True, it runs the body. Then it checks again. It stops only when the condition becomes False.

while condition:     # ← check condition each time
    # body runs if condition is True
    # (can be thousands of lines)
# code here runs AFTER the loop ends

Boolean — the True/False type

A bool is Python's fourth data type (after int, float, str). It has exactly two possible values:

True

Loop keeps running
Game is active

False

Loop stops
Game exits

Watch the loop execute — step by step

The running flag starts as True. Each frame, the loop checks it. Click to simulate what happens when the player closes the window:

Click "Next frame" to start the simulation.
Why a flag? We could call sys.exit() directly when we detect QUIT, but using a running flag is cleaner: it lets the loop finish its current frame (saving data, playing a sound) before exiting gracefully.

The Event Queue

Between frames, the operating system collects everything the user did — key presses, mouse moves, window clicks — and places each event in a queue. Your code processes them all with pygame.event.get().

🔄 Pattern Recognition

The event loop matches each incoming event against known patterns (event.type == pygame.QUIT). This is the same idea as spam filtering and facial recognition — check each item against a known pattern and act accordingly.

How the queue works

Click the event types below to simulate processing the queue:

KEYDOWN K_UP
→
KEYDOWN K_RIGHT
→
QUIT

Event types in Pygame

ConstantWhen it firesExtra info on event
pygame.QUITPlayer clicks the ✕ buttonNone
pygame.KEYDOWNKey is pressed downevent.key — which key
pygame.KEYUPKey is releasedevent.key
pygame.MOUSEBUTTONDOWNMouse button clickedevent.pos, event.button
for loop inside while loop pygame.event.get() returns a list of events. The for loop processes them one by one. Nested loops (a loop inside another loop) are a very common programming pattern — you're already using two loop types at once.

Frames Per Second — keeping perfect time

FPS (frames per second) is how many times the game loop runs every second. Without a clock, the loop runs as fast as possible — thousands of times per second — making the game unplayable and burning CPU.

💡 Abstraction

clock.tick(8) hides all the timing complexity — sleep calculations, OS scheduling — behind a single function call. You don't need to know how it works, only what it does: "make this frame last at least 1/8 of a second".

See the effect of different FPS values

8 Each dot = one frame

What happens at different speeds?

SNAKE_SPEEDFrames / secEffect on game
22Very slow — snake moves like it's underwater
88Default — comfortable beginner speed
1515Challenge mode — harder to control
6060Unplayable — snake crosses the grid in 0.3 s
1 frame = 1 snake move In Step 4, the snake moves one cell every frame. So FPS directly controls how fast the snake moves. SNAKE_SPEED = 8 means the snake moves 8 cells per second. This is why it's called SNAKE_SPEED!

Visualising the Animated Game Loop

Every frame, the same four things happen in the same order. Watch the loop cycle at SNAKE_SPEED = 8:

CT: Algorithm Design — the game loop IS an algorithm

📋 Algorithm Design

An algorithm is a precise, step-by-step procedure that solves a problem. The game loop is an algorithm — it has clear steps, a termination condition (running = False), and produces a predictable result (smooth game play) every time.

The game loop as pseudocode

ALGORITHM GameLoop:
  running ← True
  WHILE running = True:
    FOR each event in event_queue:
      IF event = QUIT THEN running ← False
      IF event = KEY_ESC THEN running ← False
    END FOR
    fill screen with BG colour
    push frame to display
    wait until 1/SNAKE_SPEED seconds have passed
  END WHILE
  quit pygame

This pseudocode maps exactly to the Python code you'll write. Pseudocode is a CT tool — it lets you plan logic without worrying about syntax.

How this algorithm evolves through the steps

2

Now (Step 2)

Events + fill + flip + tick. Minimal — a living window with no game yet.

3

Step 3: Direction control added

Arrow key events now change a direction variable inside the event loop.

4

Step 4: Snake moves + draw

After events: move snake, check food, check collision. Then draw snake + food on screen.

5–9

Steps 5–9: More logic, same structure

Functions, wrap-around, high score, OOP — all added inside this same loop skeleton.

The Code — Step 2

Run this in Thonny. The dark window stays open — try pressing Escape or clicking the ✕ to close it.

# Step 2-1: Create clock and the running flag (bool: True = keep going)
clock   = pygame.time.Clock()
running = True

# Step 2-2: The game loop — repeats 8 times per second while running is True
while running:

    # Step 2-3: Process every event the OS collected since last frame
    for event in pygame.event.get():
        if event.type == pygame.QUIT:        # player clicked ✕
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE: # player pressed Escape
                running = False

    # Step 2-4: Draw — fill background then push the frame to screen
    screen.fill(BG)
    pygame.display.flip()

    # Step 2-5: Limit loop to SNAKE_SPEED frames per second
    clock.tick(SNAKE_SPEED)

# Step 2-6: Loop ended — clean up Pygame
pygame.quit()

Try It — Exercises

Each exercise reinforces a specific concept. Predict the outcome first, then run.

1

Speed experiment 🔄 Pattern

Try SNAKE_SPEED = 2, then 30, then 60. How does this affect how fast the snake will move in later steps? (Hint: 1 frame = 1 cell moved.)

2

Event detective 🔄 Pattern

Add print(event.type, event) inside the for event loop. Run the program, then press keys and move the mouse over the window. What integers do you see? What event fires when you press a key?

3

Add a third exit key 📋 Algorithm

Add code so pressing Space also exits. In Pygame, space is pygame.K_SPACE. Where in the algorithm should you add this check?

4

Count the frames 💡 Abstraction

Add a variable frame_count = 0 before the loop. Inside the loop, add frame_count += 1. After the loop, add print("Total frames:", frame_count). Run for about 5 seconds, then close. How many frames ran? Does it match SNAKE_SPEED × seconds?

⚠️ Common Mistakes — Spot These Before You Start

These are the three errors beginners make most often in Step 2. Read them now so you can recognise them in your own code.

✗ Mistake 1: Missing pygame.display.flip()
    screen.fill(BG)
    # pygame.display.flip()  ← forgot this!
    clock.tick(SNAKE_SPEED)
🪲 What happens: The window opens but stays completely black. Nothing ever appears — not even the background colour.
    screen.fill(BG)
    pygame.display.flip()   # ← push the frame to screen
    clock.tick(SNAKE_SPEED)
✗ Mistake 2: Missing clock.tick()
    screen.fill(BG)
    pygame.display.flip()
    # clock.tick(SNAKE_SPEED)  ← forgot this!
🪲 What happens: The loop runs at full CPU speed — thousands of frames per second. In Step 4 the snake will cross the whole screen in a fraction of a second. Impossible to play.
    screen.fill(BG)
    pygame.display.flip()
    clock.tick(SNAKE_SPEED)  # ← cap to 8 fps
⚡ Mistake 3: Code accidentally outside the loop (indentation)
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
screen.fill(BG)          # ← outdented! outside loop
pygame.display.flip()    # ← outside loop
🪲 What happens: fill and flip run once before the loop, then nothing ever updates. The screen stays blank after the first frame.
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    screen.fill(BG)       # ← indented: inside loop ✓
    pygame.display.flip() # ← inside loop ✓

✅ Quick Check — Are You Ready?

Three questions — not graded. They just help you spot any gaps before the activities.

1 What does setting running = False inside the event loop do?
2 What does clock.tick(8) do each frame?
3 Pick the correct order for the four actions every game-loop frame:

You've covered all the concepts for Step 2. Time to apply them.

Start Activities → Tier 1 → 2 → 3 → 4
Previous← Variables & Setup