Pygame Shmup Part 8: Sound and Music

Tags: python tutorial gamedev pygame

This is part 8 of our “Shmup” project. If you haven’t already read through the previous parts, please start with Part 1. In this lesson we’ll add sound effects and music to the game.

About this series

In this series of lessons we’ll build a complete game using Python and Pygame. It’s intended for beginning programmers who already understand the basics of Python and are looking to deepen their Python understanding and learn the fundamentals of programming games.

You can watch a video version of this lesson here:

The power of sound

Good audio (sound and music) is the single most effective way to add “juice” to a game. Juice is an informal game design word for the things that make a game fun and engaging. It’s sometimes also called “game feel.”

Just as with graphics, finding the right sounds for your game can be challenging. OpenGameArt is a great place for finding audio assets, and it can be a lot of fun to search through the site looking for sounds, but we’re going to look at another way to create our game’s sound effects.

Making custom sounds

We’re going to use a really great tool called Bfxr to generate the sounds we need for our Shmup game. Bfxr looks like this:

Don’t be intimidated by all those sliders and the audio jargon names. The buttons on the left side will randomly generate a sound of that type. Try clicking the “Shoot” button a few times. The sounds that are generated will be saved in the list below the buttons.

For the Shmup game, we will need a “shoot” sound and an “explosion” sound. When you’ve found a sound you want, click on the “Export Wav” button (NOT the “Save to Disk” button).

Next, we’ll create a “snd” folder (like we did for images) and put the WAV files in there. Here are the sounds I chose:

Note that there are two explosion sounds. This way, we can choose randomly between them and have a little variety in our meteor explosions.

Last, but not least, we need some music. Feel free to browse OpenGameArt, or you can use this one:

Notice that on the page above, the artist has specified “Attribution Instructions”. These are the requirements that the artist has chosen to license the music to you. In brief, it means we have to give credit to the artist. We’ll copy & paste that statement in the top of our program.

Adding sound to the game

We’re ready to add the sounds into the game. First, we need to specify where our sound folder is:

# Frozen Jam by tgfcoder <https://twitter.com/tgfcoder> licensed under CC-BY-3
# Art from Kenney.nl
import pygame
import random
from os import path

img_dir = path.join(path.dirname(__file__), 'img')
snd_dir = path.join(path.dirname(__file__), 'snd')

Next, we need to load the sound files. We will do that in the same location where we’re loading the graphics. Let’s do the shooting sound first:

# Load all game sounds
shoot_sound = pygame.mixer.Sound(path.join(snd_dir, 'pew.wav'))

Now we have the sound loaded and assigned to the variable shoot_sound so that we can refer to it. We want the sound to play whenever the player shoots, so let’s add that to the shoot() method:

    def shoot(self):
        bullet = Bullet(self.rect.centerx, self.rect.top)
        all_sprites.add(bullet)
        bullets.add(bullet)
        shoot_sound.play()

That’s all there is to it. It feels much nicer to shoot now!

Next, let’s add the explosion sounds. We’ll load both of them and put them in a list:

# Load all game sounds
shoot_sound = pygame.mixer.Sound(path.join(snd_dir, 'pew.wav'))
expl_sounds = []
for snd in ['expl3.wav', 'expl6.wav']:
    expl_sounds.append(pygame.mixer.Sound(path.join(snd_dir, snd)))

To make the explosions play, we’ll randomly select one of them whenever we destroy a meteor:

    # check to see if a bullet hit a mob
    hits = pygame.sprite.groupcollide(mobs, bullets, True, True)
    for hit in hits:
        score += 50 - hit.radius
        random.choice(expl_sounds).play()
        m = Mob()
        all_sprites.add(m)
        mobs.add(m)

Music

The last thing to do is add some background music, which will bring a lot of personality and emotion to a game. Music works a little bit differently from sound, because you want it constantly streaming in the background.

First, load the music:

expl_sounds = []
for snd in ['expl3.wav', 'expl6.wav']:
    expl_sounds.append(pygame.mixer.Sound(path.join(snd_dir, snd)))
pygame.mixer.music.load(path.join(snd_dir, 'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
pygame.mixer.music.set_volume(0.4)

This music file happens to be rather loud, and we don’t want it to overpower the other sounds, so we’ve also set the volume to 40% of maximum.

To play music, you just have to choose where in the code the song should start, which in our case is right before the game loop starts:

score = 0
pygame.mixer.music.play(loops=-1)
# Game loop
running = True

The loops parameter is how you specify the number of times you want the song to repeat. By setting loops to -1 we have it repeat infinitely.

Try it out - doesn’t the game feel so much better now? We haven’t changed any of the gameplay, but the music and sound effects make for a much richer experience. Experiment with different sounds and see how it affects the game feel.

In the next lesson, we’ll add some shields to the player so we don’t die so easily.

Full code for this part

Part 9: Shields

Comments