Adding Background Music
Introduction: Setting the Mood
Sound is 50% of the game experience. While sound effects (SFX) provide feedback for actions, background music (BGM) creates the atmosphere. In this lesson, we will integrate a looping soundtrack that heightens the tension while you play but gracefully stops when you lose.
Pygame handles audio in two distinct ways, and choosing the right one is key to performance and control.
pygame.mixer.Sound vs. pygame.mixer.music
You've already used pygame.mixer.Sound for your "point" and "hit" sounds. These are meant for short clips that need to be played instantly. They are loaded entirely into your computer's RAM, which allows Pygame to play multiple sounds at once (like several explosions or shots overlapping).
Background tracks are different. They are often several megabytes in size. If you loaded a 5-minute song into RAM as a Sound object, your game would use a lot of unnecessary memory. Instead, Pygame provides the pygame.mixer.music module. This module streams the file from your hard drive as it plays, similar to how a video app streams a movie.
Because it's a stream, Pygame only allows one music track to be active at a time.
Loading and the Music Lifecycle
The life of a music track in your game follows three distinct stages:
load(): This happens once during your setup phase. It tells Pygame which file to prepare.play(): This starts the stream.stop(): This kills the stream immediately.
We load the file before the while loop starts. This prevents the game from stuttering later when it tries to start the music.
Loop Logic: The Magic of `-1`
When you start the music, you usually want it to play for as long as the game is running. If the song ends, it should restart from the beginning automatically.
The argument -1 is a special flag in Pygame that means "loop indefinitely." If you passed 0, it would play once and stop. If you passed 1, it would play once and then repeat once (playing twice total).
Synchronizing Audio with Game States
The secret to a polished game is making the audio react to the player's journey. We don't want the music playing on the silent Start Screen or the somber Game Over screen.
- Entering Play: Start the music when the state changes from
"start"to"playing". - Collision: Stop the music the moment the player hits an obstacle. This silence creates a dramatic impact, signaling that the "session" has ended.
- Restarting: When the player restarts from the Game Over screen, we must call
play(-1)again to restart the track from the beginning.
Proper Cleanup
It's good practice to stop all music before the program exits. While pygame.quit() generally handles this, adding an explicit pygame.mixer.music.stop() at the very end of your main() function ensures a clean shutdown of the audio hardware.
Conclusion
You've now mastered the two pillars of game audio: overlapping Sound effects and streaming background music. Your game now has a soul! In the final unit, we'll add a difficulty curve to keep the player coming back for more.
