December 31, 2018. Officially the last day of the year. I wanted to end this year by finishing what I started: Creating the last post for how to make a Space Shooter in Pygame and Python. It feels right to wrap things up and start something new and fresh for the new year. There are a number of machine learning and game development projects that I am looking forward to getting started on and sharing with all of you in the next year.
In the final Space Shooter tutorial, we are going to finish two major components: creating a game menu, and adding sound and music to the game.

THE CODE FOR THIS TUTORIAL CAN BE FOUND ON GITHUB.
Adding sound and music
The first task we will talk about is adding sounds and music to our game. Unless we are in the vacuum of space where the large empty spaces between stars and planets provide no molecules for sound waves to travel, then sound provides a much more immersive, realistic, and beautiful experience. The right sounds and music can be used to make a gaming experience more memorable and enjoyable.
Let’s get started by finding the file where all of our sounds are located:
1 |
sound_dir = path.join(path.dirname(__file__), 'sounds') |
This bit of code locates the path of the sounds folder and is written under where we import the necessary packages at the top of the file.
We must also initialize the sound mixer for Pygame.
1 |
pygame.mixer.init() # initialize for sound |
Next, in the main( ) game loop, let’s load all of the game sounds and give them variable names so we can call them in our game when we need to.
1 2 3 4 5 6 7 8 9 10 |
# load game sounds bullet_sound = pygame.mixer.Sound(path.join(sound_dir, 'laser.wav')) bullet_sound.set_volume(0.25) # volume enemy_bullet_sound = pygame.mixer.Sound(path.join(sound_dir, 'enemy_laser.wav')) missile_sound = pygame.mixer.Sound(path.join(sound_dir, 'rocket.ogg')) missile_sound.set_volume(0.15) large_expl = pygame.mixer.Sound(path.join(sound_dir, 'large_explosion.wav')) small_expl = pygame.mixer.Sound(path.join(sound_dir, 'small_explosion.wav')) ship_expl = pygame.mixer.Sound(path.join(sound_dir, 'explosion_ship.wav')) ship_expl.set_volume(0.4) |
Let’s look at line 2. Here we load the bullet_sound used by our player ship by locating the sound file name, ‘laser.wav’, and assigning it to a variable name. Pygame has a function that allows for volume adjustment. We use this function in line 3 so the constant sounds of our bullets shooting don’t distract from the other sounds. The other sounds are the enemy bullets sounds, player missile sounds, and the three different types of explosions.
Sounds will be used throughout the game, so to keep this post from getting too complicated I will show an example of how to use the sound. To check out where else to place the sounds, you can try it out for yourself or check out the full code.
THE CODE FOR THIS TUTORIAL CAN BE FOUND ON GITHUB.
Let’s take a look at a complete example for collision detection for bullets and asteroids.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# check if a bullet hit an asteroid asteroid_hit = pygame.sprite.groupcollide(asteroids, bullets, True, pygame.sprite.collide_circle) # when asteroids are destroyed, spawn new asteroids for hit in asteroid_hit: score += 50 - hit.radius # different scores for different size asteroids large_expl.play() large_expl.set_volume(0.1) expl = Explosion(hit.rect.center, 'large', explosion_anim) all_active_sprites.add(expl) if random.random() > 0.92: powerup = PowerUp(hit.rect.center, powerup_images) all_active_sprites.add(powerup) powerups.add(powerup) new_asteroid = Asteroid(asteroid_images, all_active_sprites, asteroids) all_active_sprites.add(new_asteroid) asteroids.add(new_asteroid) |
For this instance of collision detection (and others) once we determine that a collision has occurred we need to play not only an animation, but also a sound. After the detection, let’s call the sound we want to use, large_expl for asteroid explosions, and call play( ) and set_volume( ) on the explosion in lines 6 and 7. Every time an asteroid explodes the sound will play.
Using sound in Pygame is really that simple. For other instances where sound is needed, such as bullets or missiles, find the instance where that object is used and follow it by some_sound.play( ) in the code.
Game Menu
The second task we are going to tackle is the game menu. Traditionally in older arcades games the menu served as the interface for a player to start the game or learn about the controls. If no one was playing, the game would enter a demo loop to display examples of gameplay, which would be broken if someone moved the controller or pressed a button.
Our Space Shooter will do pretty much the same, sans demo loop. When the player starts the game, we will enter the main game while loop. While the user has not pressed ‘return’ (this is our start button), we will remain in the main game loop and keep checking for either ‘return’ to be pressed or the ‘q’ key to quit the game.
We need to create the menu( ) function and call it in our main game while loop.
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 |
def menu(): '''display main menu''' pygame.mixer.music.load(path.join(sound_dir, 'SpaceShooter_Theme.wav')) pygame.mixer.music.play(-1) title = pygame.image.load(path.join(img_dir, "The_Lonely_Shooter.png")).convert_alpha() title = pygame.transform.scale(title, (WINDOWWIDTH, 81 * 2)) background = pygame.image.load('images/stars_bg.jpeg').convert() background_rect = background.get_rect() # display instructions for game arrow_keys = pygame.image.load(path.join(img_dir, 'arrowkeys.png')).convert_alpha() arrow_keys = pygame.transform.scale(arrow_keys, (150, 85)) spacebar = pygame.image.load(path.join(img_dir, 'spacebar.png')).convert_alpha() spacebar = pygame.transform.scale(spacebar, (150, 50)) DISPLAYSURF.blit(background, background_rect) DISPLAYSURF.blit(title, (0,20)) DISPLAYSURF.blit(arrow_keys, (225, 400)) DISPLAYSURF.blit(spacebar, (225, 500)) pygame.draw.rect(DISPLAYSURF, GREENYELLOW, (80, 294, 321, 35)) pygame.draw.rect(DISPLAYSURF, GREENYELLOW, (120, 345, 240, 35)) draw_text(DISPLAYSURF, "PRESS [ENTER] TO BEGIN", 35, WINDOWWIDTH/2, WINDOWHEIGHT/2, DARKGREY) draw_text(DISPLAYSURF, "PRESS [Q] TO QUIT", 35, WINDOWWIDTH/2, (WINDOWHEIGHT/2) + 50, DARKGREY) # game instructions pygame.draw.rect(DISPLAYSURF, GREENYELLOW, (50, 430, 100, 35)) pygame.draw.rect(DISPLAYSURF, GREENYELLOW, (50, 510, 100, 35)) draw_text(DISPLAYSURF, "MOVE:", 35, 100, 436, DARKGREY) draw_text(DISPLAYSURF, "SHOOT:", 35, 101, 516, DARKGREY) pygame.display.update() while True: event = pygame.event.poll() if event.type == pygame.KEYDOWN: if event.key == pygame.K_RETURN: break elif event.key == pygame.K_q: pygame.quit() sys.exit() elif event.type == QUIT: pygame.quit() sys.exit() |
There is a lot to unpack here. In lines 3 – 4, the main title music is played, and by using play(-1) the song plays in a continuous loop. The main title and star background image are loaded in lines 6 – 9.

We then load images that will display the spacebar and arrow key images to the screen in lines 12 – 15. The images are used to show the main game controls to the user before they start the game. These images are all blitted to the screen in lines 17 – 20. Game instructions are also drawn on the screen and yellow-green rectangles are drawn around them to make them stand out from the background.
Finally in lines 34 – 44, we will remain in this small loop on the menu screen until the player presses the ‘enter’ key or quits the game.
“Where and how do we use this menu?” You might ask. Why, in the main while game loop. We first need to create two boolean variables. running is True if we are still in the game loop, and show_menu is True if we are in the menu loop.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
running = True show_menu = True while running: # main game loop if show_menu: menu() pygame.time.delay(1500) # fade out menu music pygame.mixer.music.fadeout(1500) pygame.mixer.music.load(path.join(sound_dir, 'SpaceShooter_Theme2.wav')) pygame.mixer.music.play(-1) show_menu = False ###### CODE OMITTED ###### # If player dies, return to menu if player.lives == 0 and not expl_ship.alive(): pygame.mixer.music.stop() show_menu = True ###### CODE OMITTED ###### |
Once we push ‘enter’ and break out of the menu loop, a delay is called in line 6 so we don’t jump right into the game. Let’s also fade out of the menu music in line 9 and play a different song when the game starts in line 11 and 12. We then make show_menu equal False.
But how do we go back to the menu if we are out of lives? If player.lives == 0 and the animation for the ship explosion is no longer playing (explosions_ship.alive( )), then we stop the music and return to the main menu in lines 19 – 21.

Summary
Done! That ends the tutorials for the Space Fighter game using Pygame. In this tutorial we added music, sound, and a start menu to the game.
I hope those of you who read this tutorial will use the code to learn from it and make your own games and post them so others can see. I would really like to see what games you have made. Please leave a link in the comments below.
Final Note
It has been quite an adventure writing these posts and in many ways has helped me to realize what I enjoy doing. I would really like to hear back from all of you about your own personal programming adventures in the comments. In the future I am going to start working on more machine learning and computer vision posts. But if there is ever any topics you are thinking about and would like to see here, please let me know.
I hope all of you can continue to follow your goals and dreams in the new year! Happy 2019!