pyodide: loading…

[concept]Game Development with Pygame

Sound & Music

# theory

adding sound to your game

A game without sound feels dead. Pygame's mixer module handles both short sound effects (explosions, jumps, hits) and background music (looping tracks).

import pygame
pygame.init()
pygame.mixer.init()  # already called by pygame.init(), but good to know it exists

There are two separate systems and they work differently:

  • Sound effects: short clips, multiple can play at once
  • Music: one track at a time, streams from disk (good for long files)

sound effects with pygame.mixer.Sound

Sound effects are loaded into memory. Use .wav or .ogg files (mp3 support is inconsistent).

# Load sounds (do this ONCE, outside the game loop)
jump_sound = pygame.mixer.Sound("assets/jump.wav")
hit_sound = pygame.mixer.Sound("assets/hit.wav")
coin_sound = pygame.mixer.Sound("assets/coin.ogg")

# Play a sound (inside the game loop, when something happens)
if player_jumped:
    jump_sound.play()

if collision_detected:
    hit_sound.play()

Key point: Load sounds once at startup. Don't load them inside the game loop or you'll destroy your frame rate.

Volume Control

# Set volume (0.0 = silent, 1.0 = full volume)
jump_sound.set_volume(0.5)   # 50% volume
hit_sound.set_volume(0.3)    # quieter

# Get current volume
current_vol = jump_sound.get_volume()

Stopping Sounds

hit_sound.stop()          # stop this specific sound
pygame.mixer.stop()       # stop ALL sounds

background music with pygame.mixer.music

Music streams from disk instead of loading into memory. Only one track plays at a time.

# Load and play background music
pygame.mixer.music.load("assets/background.ogg")
pygame.mixer.music.set_volume(0.4)
pygame.mixer.music.play(-1)  # -1 = loop forever

# Pause / unpause
pygame.mixer.music.pause()
pygame.mixer.music.unpause()

# Stop completely
pygame.mixer.music.stop()

# Fade out over 2 seconds (smooth ending)
pygame.mixer.music.fadeout(2000)

The -1 argument is important. play(0) plays once, play(3) plays 3 extra times (4 total), play(-1) loops forever. For background music you almost always want -1.


channels: playing multiple sounds

Pygame has 8 channels by default. Each channel can play one sound at a time. When you call sound.play(), it grabs a free channel automatically.

# Need more simultaneous sounds?
pygame.mixer.set_num_channels(16)  # now 16 channels

# Reserve a channel for important sounds (so it never gets stolen)
pygame.mixer.set_reserved(1)
important_channel = pygame.mixer.Channel(0)  # channel 0 is reserved
important_channel.play(alert_sound)

If all channels are busy when you play a sound, the oldest sound gets cut off. Reserving a channel guarantees your critical sounds (like a game-over chime) always play.


common pattern: sound manager

Most games wrap their sounds in a simple manager:

class SoundManager:
    def __init__(self):
        self.sounds = {}
        self.muted = False

    def load(self, name, filepath):
        self.sounds[name] = pygame.mixer.Sound(filepath)

    def play(self, name, volume=1.0):
        if not self.muted and name in self.sounds:
            self.sounds[name].set_volume(volume)
            self.sounds[name].play()

    def toggle_mute(self):
        self.muted = not self.muted
        if self.muted:
            pygame.mixer.stop()

# Usage:
sfx = SoundManager()
sfx.load("jump", "assets/jump.wav")
sfx.load("coin", "assets/coin.ogg")

# In game loop:
sfx.play("jump")
sfx.play("coin", volume=0.5)

Gerber tip: Keep your sound loading separate from your game logic. Load everything in an init function, then just call play() during the game. Clean separation.


file formats

FormatBest ForNotes
.wavSound effectsUncompressed, fast to load, large files
.oggMusic + effectsCompressed, small files, good quality
.mp3AvoidLicensing issues, inconsistent support

Stick with .ogg for most things. Use .wav for tiny effects where loading speed matters.

# examples [2]

# example 01 · loading and playing a sound effect

Load once at startup, play when events happen. Never load inside the game loop.

1
2
3
4
5
6
7
🐍
Loading PythonSetting up pandas & numpy...

pygame needs a real window — copy this into a .py file and run it locally.

# example 02 · looping background music with fadeout

Music streams from disk. Use play(-1) for infinite loop, fadeout() for smooth transitions.

1
2
3
4
5
6
7
8
9
🐍
Loading PythonSetting up pandas & numpy...

pygame needs a real window — copy this into a .py file and run it locally.

# challenges [3]

# challenge 01/03todo
What's the difference between pygame.mixer.Sound and pygame.mixer.music? When would you use each?
pygame needs a real window. copy this into a .py file and run it locally.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
🐍
Loading PythonSetting up pandas & numpy...
# challenge 02/03todo
What does pygame.mixer.music.play(-1) do? What would play(0) and play(3) do?
pygame needs a real window. copy this into a .py file and run it locally.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
🐍
Loading PythonSetting up pandas & numpy...
# challenge 03/03todo
Why should you load all your Sound objects outside the game loop, not inside it?
pygame needs a real window. copy this into a .py file and run it locally.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
🐍
Loading PythonSetting up pandas & numpy...