Unit 12.2A · Term 2

Game Loop

The game loop is the heartbeat of a real-time game. While the application is running, it repeatedly handles events, updates game state, renders the next frame, and controls the speed of the cycle.

Learning Objective

  • 12.5.1.3 Code the game loop of the application

How Games Work

Clear Code — how games create movement from repeated frames. Starts at 01:06.

Conceptual Anchor

The Film Projector Analogy

A film creates the illusion of motion by showing many still frames in rapid succession. A game does the same thing, except each frame is produced by code: read input → update state → draw the current state → show the frame → repeat.

Frame 1
Frame 2
Frame 3
Frame 4

One Frame of the Game Loop

Handle Events
Update State
Render Frame
Control FPS
GAME LOOP
Frame 1
running True
Phase Events
Phase Purpose Typical PyGame code
1. Handle Events Read queued events such as QUIT or key presses pygame.event.get()
2. Update State Change positions, scores, timers and other game data Game logic
3. Render Clear the old frame, draw the new state and show it fill() + draw + flip()
4. Control FPS Limit how quickly frames repeat clock.tick(FPS)

Anatomy of the Game Loop

running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # update game state screen.fill(BLACK) # draw current game state pygame.display.flip() clock.tick(FPS) pygame.quit()
while running: Repeat frames

The program keeps producing frames while the control variable remains True.

pygame.event.get() Handle events

Retrieve queued PyGame events so the application can react.

screen.fill(...) pygame.display.flip() Render

Prepare the current frame and then make the complete display Surface visible.

clock.tick(FPS) Control speed

Limit the loop so it does not run unrestricted as fast as the CPU allows.

Why while running?

running = True
→
while running
→
one frame
→
running still True? ↺

How the loop ends

When a pygame.QUIT event is found, the program sets running = False. The current iteration finishes, the while condition fails on the next check, and execution continues after the loop to pygame.quit().

Event Queue

Operating system / devices

Mouse movement, keyboard actions and window controls generate events.

PyGame event queue

Events wait in a queue until your program retrieves and handles them.

pygame.event.get()

Gets the queued events so a for event in ... loop can process them.

Event queue
Events returned for processing
Add some events, then call pygame.event.get().

Why process events regularly?

The event queue has a limit and should be serviced every frame. If your application stops processing events for too long, the operating system may consider the program unresponsive.

QUIT Event Tracer

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False


                                    
Event Role in this unit
pygame.QUIT Core today: user requests that the window close
pygame.KEYDOWN Preview: a key has been pressed
pygame.KEYUP Preview: a key has been released
pygame.MOUSEBUTTONDOWN Coming later: Mouse Control
pygame.MOUSEMOTION Coming later: Mouse Control

Render Pipeline

Old frame
→
Clearscreen.fill()
→
Draw state# draw...
→
Show framedisplay.flip()

Why pygame.display.flip()?

After you prepare the current frame on the display Surface, pygame.display.flip() updates the full display so the user can see that frame.

Render Order Lab

Render Preview
fill → draw → flip
draw → fill → flip
fill → draw # no flip()
Choose an order and observe the result.

FPS Control with Clock

Command Purpose
clock = pygame.time.Clock() Create one Clock object before the game loop
clock.tick(60) Limit the loop to approximately a maximum of 60 frames per second
clock.get_fps() Estimate the current frame rate measured by the Clock
60 target/max FPS
16.7 ms ideal time per frame
600 frames in 10 seconds
Without clock.tick()
437 FPS 812 FPS 526 FPS as fast as CPU allows
With clock.tick(60)
59 FPS 60 FPS 60 FPS approximately limited
Extension: delta time preview
dt = clock.tick(60) / 1000

tick() returns elapsed milliseconds. Dividing by 1000 gives seconds. Later, during Movement & Animation, delta time can be used for frame-rate-independent motion.

Game Loop Templates

Choose a template:

Events for event in pygame.event.get():
Update # change game state
Render fill → draw → flip
Timing clock.tick(FPS)

Build the Game Loop

Click the phases in the correct order for one frame.

Correct order: Events → Update → Render → FPS → Next Frame.

What Belongs Where?

Extension: display FPS on the game screen

This requires pygame.font, font.render() and blit(), so it is intentionally an extension rather than core Game Loop content.

font = pygame.font.SysFont("Arial", 24) fps_text = font.render( f"FPS: {clock.get_fps():.0f}", True, (0, 255, 0) ) screen.blit(fps_text, (10, 10))

Game Loop Error Lab

Identify the most important game-loop problem.

Pitfalls & Common Errors

Not processing events

A game window must keep servicing its event queue. Otherwise it can become unresponsive and the operating system may report it as frozen.

No clock.tick() = unrestricted loop speed

Without an FPS limit, the loop can run as quickly as the machine allows, wasting resources and making frame-dependent behaviour inconsistent.

Drawing before clearing

If you draw an object and then call screen.fill(), the background covers that object before the frame is shown.

Missing display.flip()

You can prepare a new frame on the Surface but still fail to show it. The display update belongs after drawing the current frame.

Creating Clock() inside every frame

Create the Clock once before the loop, then call clock.tick() each iteration.

pygame.quit() inside the loop

Normally pygame.quit() belongs after the loop finishes. Calling it every frame uninitialises modules while the program is still running.

Graded Tasks

Remember

Name the three core game-loop phases and state the role of clock.tick().

Understand

Explain the purpose of while running: and how a pygame.QUIT event causes the loop to finish.

Understand

Explain what the event queue is and why pygame.event.get() should be called regularly.

Apply

Write the event-handling code that sets running = False when the user closes the window.

Apply

Change a background variable when the user presses Space, then use that variable when rendering the next frame.

Apply

Add pygame.time.Clock() and limit a game loop to approximately 60 FPS.

Analyze

Find and explain all problems in a loop that never processes events, clears the screen after drawing, and creates a new Clock every frame.

Create

Complete a clean game-loop template with clearly separated Events, Update, Render and FPS control sections.

Exam Practice

Q1: Complete the missing code. [5]

running = True while ______: for event in pygame.event._____(): if event.type == pygame._____: running = False pygame.display._____() clock._____(60)
Reveal marking points
while running: pygame.event.get() pygame.QUIT pygame.display.flip() clock.tick(60)

Q2: Explain why pygame.event.get() must be called regularly. [2]

Reveal marking points
It retrieves/processes queued application events. If the queue is not serviced, the application may become unresponsive and events can be lost when the queue fills.

Q3: State the correct rendering order. [3]

Reveal marking points
1. Clear/fill the previous frame 2. Draw the current game state 3. Update/show the display with flip() or an appropriate display update

Q4: A game uses clock.tick(50). Calculate the ideal time available per frame in milliseconds. [2]

Reveal marking points
1000 ÷ 50 = 20 ms per frame.

Self-Check Quiz

Eight quick checks Click each answer to reveal
1. What are the three core phases of a game loop?
Click to reveal answer
2. What does pygame.event.get() return?
Click to reveal answer
3. Which event is generated when the user requests the window to close?
Click to reveal answer
4. Why is screen.fill() normally called before drawing the current frame?
Click to reveal answer
5. What does pygame.display.flip() do?
Click to reveal answer
6. What does clock.tick(60) do?
Click to reveal answer
7. Approximately how many milliseconds are available per frame at 60 FPS?
Click to reveal answer
8. Where should pygame.quit() normally be placed?
Click to reveal answer