Python Arcade Sound Effects and Postgres

Have a Database Problem? Speak with an Expert for Free
Get Started >>

Introduction

This is part 8 of a multi-part series of articles teaching how to build a 2D video game. In this part 8, we add how to use Python Arcade for Sound Effects and Postgres for writing and reading Sprites. In this part, we learn how to add a background song and various sound effects, including when a snowball is thrown, when an enemy is hit by the snowball, and when the player dies. In the articles following this part, we’ll learn to keep score, and add a system for tracking and changing game difficulty. Depending on demand, we may also add multiplayer capability.

Prerequisites

  • The full source code, images, and sound files are all available for download.

  • Python Arcade docs. We use the Arcade framework for quite a bit of the functionality in this 2D Python Arcade game.

  • IMPORTANT: study part 1 through part 7 where we learned to create and set up a game window with PostgreSQL, how to create Sprites with images and Sprite Lists, how to respond to key presses, how to move the Player’s Sprite icon on the screen based on those key presses, how to move enemies with some intelligence, to fire bullets with the space bar, bullet movement, and collisions between Sprites and Sprite Lists.

Python libraries for the videogame

Be sure to use PIP to install the following libraries.

1
2
3
4
5
6
7
8
import arcade # Game-oriented library for Python.
import math # For some math / movement physics-related functions.
import random # For generating random numbers for enemy movement.
import os # For accessing the file system to load images and sounds.
import sys # For getting resource files into the game.
import psycopg2 # For Postgres data retrieval for screens.
import pyautogui # For getting monitor resolution to make sure our window is not too large.
from datetime import datetime, timedelta # For seeding random number generation.

In this part, before we get to sounds, we’ll quickly review the check_for_collision_with_list() function.

check_for_collision_with_list syntax

1
list_of_sprite_collisions = arcade.check_for_collision_with_list(one_sprite, sprites_list)

Now we will dive in by setting up some sounds.

Set up sounds with Arcade

The first thing to do is assign some Arcade sound-specific objects with our MP3 files, so that these objects can be called later on to play.

1
2
3
4
5
6
self.sound_song = arcade.load_sound("./resources/sounds/song-maple-leaf-rag.mp3")
self.sound_snowball_throw = arcade.load_sound("./resources/sounds/woosh.mp3")
self.sound_gasp_of_death = arcade.load_sound("./resources/sounds/gasp.mp3")
self.sound_munching = arcade.load_sound("./resources/sounds/smack-lips.mp3")
self.sound_burp_extended = arcade.load_sound("./resources/sounds/burp-super.mp3")
self.sound_powerup = arcade.load_sound("./resources/sounds/powerup.mp3")

Next, when the game begins, we’ll start our background song playing. Arcade handles sounds in a very simplistic manner in the current version, not allowing for volume control, any kind of “play in background” parameter, or repeat. So our background song is long enough for most games but if you play long enough, the song will end and not restart. As far as “layers”, the other sound effects you play will not interrupt or otherwise disrupt the “background” song. They will blend seamlessly. The makers of the Arcade library are working on more sound parameters for a later version of Arcade.

Play background song with Arcade

Below is a portion of the code in our “start new game” function. See full code file we linked to above for the entirety of this function. Notice at the bottom of this function where we start playing the game’s theme song.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    def start_new_game(self):
        self.frame_count = 0
        self.game_over = False
        # Initialize our
        # Arcade Sprite lists.
        self.list_all_sprites = arcade.SpriteList()
        self.list_enemies = arcade.SpriteList()
        self.list_snowballs = arcade.SpriteList()
        self.list_player_lives = arcade.SpriteList()
        self.list_blocks = arcade.SpriteList()
        # Set up a title window message image
        # as a Sprite so we can control it.
        self.title = PlayerSprite("./resources/images/title.png", SCALE * 2.5)
        # Set up the player Sprite and some
        # of its traits.
        self.player_sprite = PlayerSprite("./resources/images/penguin.png", SCALE)
        self.list_all_sprites.append(self.player_sprite)
        self.lives = 3
        # Play the song that will
        # play for entire game.
        arcade.play_sound(self.sound_song)

Now we’ll finish with taking the code for collision detection we wrote during the last session and adding in sound effects when collisions occur.

Add sound to Sprite collisions

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# Go through all bullets (snowballs) currently on screen.
for snowball in self.list_snowballs:
    # Create list of enemies impacted by current bullet.
    enemies = arcade.check_for_collision_with_list(snowball, self.list_enemies)
    # IF any hits, go through all enemies hit by current bullet.
    for enemy in enemies:
        # Play "powerup" sound when Player
        # hit an enemy with a bullet.
        arcade.play_sound(self.sound_powerup)
        # Increase to player score coming in next
        # part of this multi-part article.
        # "Kill" the enemy by removing them from all
        # sprite lists.
        enemy.remove_from_sprite_lists()
        # Delete the snowball that impacted the enemy.
        snowball.remove_from_sprite_lists()

# Cycle through all enemy Sprites with for loop.
for enemy in self.list_enemies:
    # Check for impact between current enemy and all ice blocks in ice block Sprite list.
    any_collisions = arcade.check_for_collision_with_list(enemy, self.list_blocks)
    if len(any_collisions) > 0:
        # Current enemy in for loop hit a block.
        # Reverse direction to opposite with added
        # randomness.
        # The added random factor decreases the chances
        # of the enemy getting
        # stuck at the obstacle they impacted.
        random.seed(datetime.now() + timedelta(0,enemy_number))
        x_rand = random.randint(1, 50)
        if x_rand < 25:
            dir_x *= -2
        else:
            dir_y *= -2
        # Shift enemy Sprite direction based on above calculations multiplied by enemy speed.
        enemy.change_x = dir_x * (enemy_speedy)
        enemy.change_y = dir_y * (enemy_speedy)
        # Shift enemy Sprite position based on the above direction change.
        enemy.center_x += enemy.change_x
        enemy.center_y += enemy.change_y
        enemy.timer_rand = 0
        # Set timer for "smart moving" to ~2 seconds to
        # continue in this new direction so the
        # enemy for sure gets away from the obstacle
        # they hit before they change direction again.
        enemy.timer_smart = int(fps * 2)
    enemy.update()

# Check for impact between player Sprite and all obstacles.
any_impacts = arcade.check_for_collision_with_list(self.player_sprite, self.list_blocks)
if len(any_impacts) > 0:
    # Player collided with an obstacle, so
    # change direction facing angle to
    # opposite of before.
    self.player_sprite.angle *= -1
    self.player_sprite.change_x = -math.sin(math.radians(self.player_sprite.angle)) * self.player_sprite.speed
    self.player_sprite.change_y = math.cos(math.radians(self.player_sprite.angle)) * self.player_sprite.speed
    self.player_sprite.center_x += self.player_sprite.change_x
    self.player_sprite.center_y += self.player_sprite.change_y

# Check for hit between player Sprite and all enemy Sprites.
enemies = arcade.check_for_collision_with_list(self.player_sprite, self.list_enemies)
# If list of enemies collided created above has at least one enemy in it.
if len(enemies) > 0:
    # Play three of the sounds we set up earlier:
    arcade.play_sound(self.sound_gasp_of_death)
    arcade.play_sound(self.sound_munching)
    arcade.play_sound(self.sound_burp_extended)
    self.eaten = True
    # Remove a life from
    # count of remaining lives.
    if self.lives > 0:
        self.lives -= 1
        # Call respawning function.
        self.player_sprite.respawn()
        # If you want the hit to destroy the enemy,
        # add the following line of code:
        #   enemies[0].remove_from_sprite_lists()
        # Leaving enemy alive after impact ensures
        # the game can go on forever.
        self.list_player_lives.pop().remove_from_sprite_lists()
    else:
        self.game_over = True
else:
    self.eaten = False

Conclusion

In this part 8, we learned how to use Python Arcade for Sound Effects and Postgres for writing and reading Sprites used for drawing the screen. We learned how to add a background song and various sound effects, including when a bullet is fired, when an enemy is impacted by the snowball, and when the player dies and is eaten by an enemy. In the articles following this part, we’ll learn to keep and modify score, display that score on the screen, and add tracking and changing game difficulty. Depending on demand, we may also later add multiplayer capability.

Pilot the ObjectRocket Platform Free!

Try Fully-Managed CockroachDB, Elasticsearch, MongoDB, PostgreSQL (Beta) or Redis.

Get Started

Keep in the know!

Subscribe to our emails and we’ll let you know what’s going on at ObjectRocket. We hate spam and make it easy to unsubscribe.