Game Loop
The game loop is the heartbeat of every game. It runs continuously — handling events, updating state, and rendering visuals — dozens of times per second.
Learning Objectives
- 12.5.1.3 Code the game loop of the application
Conceptual Anchor
The Film Projector Analogy
A movie projector shows 24 frames per second — each frame is a still image, but played fast they create the illusion of motion. A game loop does the same: clear screen → draw new frame → show it → repeat. The faster this cycle runs (FPS), the smoother the game feels.
Rules & Theory
The 3 Phases of a Game Loop
| Phase | What Happens | Code |
|---|---|---|
| 1. Handle Events | Process user input (keys, mouse, quit) | pygame.event.get() |
| 2. Update State | Move objects, check collisions, update scores | Game logic code |
| 3. Render (Draw) | Clear screen, draw everything, display | screen.fill() + draw + flip() |
FPS Control with Clock
| Command | Purpose |
|---|---|
clock = pygame.time.Clock() |
Create a Clock object |
clock.tick(60) |
Limit loop to 60 FPS maximum |
clock.get_fps() |
Get actual frames per second |
Event Types
| Event | When It Fires |
|---|---|
pygame.QUIT |
User clicks the window close button (✕) |
pygame.KEYDOWN |
A key is pressed down |
pygame.KEYUP |
A key is released |
pygame.MOUSEBUTTONDOWN |
A mouse button is pressed |
pygame.MOUSEMOTION |
The mouse is moved |
Worked Examples
1 Standard Game Loop Template
import pygame
import sys
pygame.init()
# --- Setup ---
WIDTH, HEIGHT = 800, 600
FPS = 60
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game Loop Demo")
clock = pygame.time.Clock()
# --- Colors ---
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# --- Game Loop ---
running = True
while running:
# Phase 1: HANDLE EVENTS
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# Phase 2: UPDATE STATE
# (game logic goes here)
# Phase 3: RENDER
screen.fill(BLACK)
# (draw objects here)
pygame.display.flip()
# Control FPS
clock.tick(FPS)
pygame.quit()
sys.exit()2 Showing FPS Counter
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("FPS Counter")
clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 24)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((30, 30, 30))
# Display current FPS
fps_text = font.render(f"FPS: {clock.get_fps():.0f}",
True, (0, 255, 0))
screen.blit(fps_text, (10, 10))
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()Common Pitfalls
No clock.tick() = Unlimited Speed
Without clock.tick(), the loop runs as fast as the CPU allows. This wastes power,
heats the CPU, and makes game speed inconsistent across different computers.
Drawing BEFORE Filling
Always screen.fill() FIRST, then draw objects. If you draw first and then fill, your
drawings get covered!
Tasks
Name the 3 phases of a game loop and describe what happens in each.
Write a game loop that changes the background color when the user presses the Space bar.
Add an FPS counter to any PyGame application displaying current frames per second.
Self-Check Quiz
Q1: What are the 3 phases of a game loop?
Q2: What does clock.tick(60) do?
Q3: What event type is triggered when the user clicks ✕?
pygame.QUIT