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:

  1. load(): This happens once during your setup phase. It tells Pygame which file to prepare.
  2. play(): This starts the stream.
  3. stop(): This kills the stream immediately.
Python
pygame.mixer.music.load("assets/music.wav")

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.

Python
pygame.mixer.music.play(-1) # Play forever!

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.
Python
if player.colliderect(obstacle):
    hit_sound.play()        # Instant feedback
    pygame.mixer.music.stop() # Kill the background vibe
    game_state = "game_over"

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.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal