Learning Goals
3 minBy the end of this lesson you can:
- Place a
.wavor.oggfile in thesounds/folder and play it withsounds.name.play(). - Trigger a different sound effect for at least two distinct game events (click, score, collision).
- Find free, usable sound clips on freesound.org and name them correctly for Pygame Zero.
Warm-Up · Sprite Direction Recap
5 minLast lesson you animated a sprite by choosing frames based on movement direction. Predict what this snippet prints before you run it:
speed_x = -5 if speed_x < 0: facing = "left" else: facing = "right" print("Facing:", facing)
Show the answer
Output
Facing: left
Speed is negative, so the sprite faces left. The same logic will soon decide which sound to play.
New Concept · The sounds Object
12 minThink of sounds like a jukebox that already loaded every track you put in the sounds/ folder. You just say the song's name and add .play(). No loading code. No file handles. No fuss.
Folder layout
Create a folder called sounds/ next to your Python file. Drop a short audio clip inside it:
my_game/
├── mygame.py
└── sounds/
├── pop.wav
└── chime.oggRules for the filenames:
- Lowercase letters and underscores only —
big_boom.wav, notBig Boom.wav. - Extension must be
.wavor.ogg. MP3 is not supported.
Playing a sound
# play sounds/pop.wav once sounds.pop.play()
The filename without extension becomes the attribute name. pop.wav → sounds.pop. big_boom.ogg → sounds.big_boom.
Where to fire it
Call .play() inside any event hook — on_mouse_down, on_key_down, or inside update() when a collision is detected. Pygame Zero will not play the same sound twice at the same instant, so double-calls are safe.
Worked Example · Clickable Sound Button
12 minFaiz builds a simple demo: clicking a green rectangle plays a pop sound; pressing SPACE plays a chime. Two events, two different sounds. Save as sound_demo.py.
# sound_demo.py — two sounds on two events import pgzrun WIDTH = 480 HEIGHT = 320 TITLE = "Sound Demo" # Rectangle the player can click button_rect = Rect((160, 120), (160, 80)) def draw(): screen.fill("black") screen.draw.filled_rect(button_rect, "seagreen") screen.draw.text( "Click me!", center=button_rect.center, fontsize=28, color="white", ) screen.draw.text( "SPACE = chime", topleft=(10, 10), fontsize=20, color="grey", ) def on_mouse_down(pos, button): if button_rect.collidepoint(pos): sounds.pop.play() # sounds/pop.wav def on_key_down(key): if key == keys.SPACE: sounds.chime.play() # sounds/chime.ogg pgzrun.go()
Notice that on_mouse_down receives the click position. We check with collidepoint before playing — only a click inside the button triggers the sound.
pop.wav; pressing SPACE plays chime.ogg.Try It Yourself
13 minAdd a third sound — sounds.whoosh.play() — that fires when the player right-clicks anywhere on the screen. In Pygame Zero a right-click gives button == mouse.RIGHT.
Hint
def on_mouse_down(pos, button): if button == mouse.RIGHT: sounds.whoosh.play() elif button_rect.collidepoint(pos): sounds.pop.play()
Use clock.schedule_interval to play sounds.tick.play() every 2 seconds — like a metronome. Stop it after 8 seconds with clock.unschedule.
Hint
import pgzrun WIDTH = 400 HEIGHT = 300 tick_count = 0 def play_tick(): global tick_count sounds.tick.play() tick_count += 1 if tick_count >= 4: clock.unschedule(play_tick) clock.schedule_interval(play_tick, 2) pgzrun.go()
Mini-Challenge · Debug Nurul's Noisy Button
8 minNurul wanted her button to play a sound only when clicked inside. Instead, the sound plays wherever she clicks. Find the two bugs:
# nurul_sound.py — buggy
import pgzrun
WIDTH = 400
HEIGHT = 300
btn = Rect((100, 100), (200, 80))
def draw():
screen.fill("navy")
screen.draw.filled_rect(btn, "orange")
def on_mouse_down(pos, button):
sounds.pop.play() # Bug 1
if btn.collidepoint(pos):
pass
pgzrun.go()Show the fixes
# nurul_sound.py — fixed import pgzrun WIDTH = 400 HEIGHT = 300 btn = Rect((100, 100), (200, 80)) def draw(): screen.fill("navy") screen.draw.filled_rect(btn, "orange") def on_mouse_down(pos, button): if btn.collidepoint(pos): # Fix 1: guard the sound with the collision check sounds.pop.play() # Fix 2: play inside the if block, not before it pgzrun.go()
Bug 1: sounds.pop.play() was before the if, so it always ran. Bug 2: the pass meant nothing happened inside the correct branch. Swap them.
It works if…
the pop sound plays only when you click inside the orange rectangle
Recap
3 minDrop a .wav or .ogg file into the sounds/ folder next to your Python file. Pygame Zero loads it automatically — you just callsounds.filename.play() inside any event hook or in update()when a game condition is met. Lowercase filenames, no spaces.
Vocabulary Card
- sounds
- A Pygame Zero object that auto-loads every file in the
sounds/folder. Attribute name = filename without extension. - .play()
- Plays a sound once from the beginning. Safe to call multiple times — Pygame Zero queues simultaneous calls.
- freesound.org
- A Creative Commons library of free audio clips you can download and use in your games.
- .wav / .ogg
- The two audio formats Pygame Zero accepts for sound effects. MP3 is not supported.
Homework
4 minFind two short sound clips on freesound.org(search "pop" and "beep"). Download them as .wav, rename them pop.wav and beep.wav, and place them in sounds/. Write a Pygame Zero program that draws two coloured rectangles and plays a different sound when you click each one. Save as two_sounds.py and bring a screenshot to the next class.
Sample · two_sounds.py
# two_sounds.py — two buttons, two sounds import pgzrun WIDTH = 480 HEIGHT = 300 TITLE = "Two Sounds" rect_a = Rect((60, 110), (140, 80)) rect_b = Rect((280, 110), (140, 80)) def draw(): screen.fill("black") screen.draw.filled_rect(rect_a, "tomato") screen.draw.text("POP", center=rect_a.center, fontsize=30, color="white") screen.draw.filled_rect(rect_b, "dodgerblue") screen.draw.text("BEEP", center=rect_b.center, fontsize=30, color="white") def on_mouse_down(pos, button): if rect_a.collidepoint(pos): sounds.pop.play() elif rect_b.collidepoint(pos): sounds.beep.play() pgzrun.go()
Colours and label text are yours to choose. The key skill: two separate collidepoint guards, each playing its own sound.