# Game Python Postgres with Sound

## Introduction

In this part, we continue building a game with Python and Postgres with Sound as part 7 of a multi-part series of lessons where the final result will be a simple 2D graphical top-down-view videogame somewhat like PacMan in that the goal is to acquire powerups while avoiding monsters. We are using Python’s “Arcade” library for its gaming-related functions and methods. We used Postgres to read and write screen and object (player, enemies, obstacles, and power-ups) data. In this lesson we will add sound to give the game more life. In future lessons in this series, we will add various graphics, a “save game” feature, multi-player, and even a screen editor/builder.

## Prerequisites

See part 1 through 6, where we learned how to draw a screen, create tables in Postgres for storing and reading screen data and screen objects as Sprites, reading keys to control player movement, added random movements to the monsters, collision detection, and a bit of intelligent player tracking to the monsters. Please study the previous parts of this lesson, starting at Build game with Python and draw a screen.

We will assume you followed the previous parts of this series, we’ll leave out creating the Postgres tables and re-doing the details of setting up a window with Arcade, except in the source code at the bottom of this part seven. So, before the final code at the bottom, we’ll briefly go over some of what we covered in previous parts of the overall lesson.

## Random Sprite movement

random_compass = random.randint(1, 8)
if random_compass == 1:
y += 2
if random_compass == 2:
x += 2
y += 2
if random_compass == 3:
x += 2
if random_compass == 4:
x += 2
y -= 2
if random_compass == 5:
y -= 2
if random_compass == 6:
y -= 2
x -= 2
if random_compass == 7:
x -= 2
if random_compass == 8:
x -= 2

## Intelligent Sprite movement

if player_y > monster_y:
monster_y += 2
if player_x > monster_x:
monster_x += 2
if player_y < monster_y:
monster_y -= 2
if player_x < monster_x:
monster_x -= 2

The code above code compares the location cooredinates of the player with the position of a monster. If the monster is above the player, the monster’s “monster_y” value is incremented.

## Full source code

import psycopg2
import random

# connect to database
t_host = "PostgreSQL database host address"
t_port = "5432"
t_dbname = "database name"
t_user = "database user name"
db_conn = psycopg2.connect(host=t_host, port=t_port, dbname=t_dbname, user=t_user, password=t_pw)
db_cursor = db_conn.cursor()

# initialize globals
id_screen = 0
t_title = ""
i_width = 0
i_height = 0
t_color = ""
i_enemy_hit = 0
i_hit_points = 100
i_points = 0
i_lives = 3
t_hit_sound = []

@app.route("/main")

def getScreenFromDB():
# Get columns for first row/
#   screen using "select top 1"
s = ""
s += "SELECT TOP 1"
s += " id"
s += ", t_color"
s += ", t_title"
s += ", i_height"
s += ", i_width"
s += " FROM tbl_screens"
s += " ORDER BY i_order ASCENDING"
try:
db_cursor.execute(s)
id_screen = db_cursor.fetch("id")
t_color_screen = db_cursor.fetch("t_color")
t_title = db_cursor.fetch("t_title")
i_height = db_cursor.fetch("i_height")
i_width = db_cursor.fetch("i_width")
except psycopg2.Error as e:
t_msg = "SQL error: " + e + "/n SQL: " + s
return render_template("error.html", t_msg = t_msg)
db_cursor.close

def getObjectsFromDB():
# Get objects data from tbl_screens_objects in Postgres
s = ""
s += "SELECT"
s += " id"
s += ", t_obj_name"
s += ", t_obj_type"
s += ", t_obj_img_URL"
s += ", i_y"
s += ", i_x"
s += ", t_color_hit"
s += ", t_properties"
s += ", t_hit_sound"
s += ", t_hit_action"
s += ", b_hit_possible"
s += ", b_hit_destroys_it"
s += ", b_hit_awards"
s += ", n_hit_awards"
s += ", n_hit_damage"
s += " FROM tbl_screens_objects"
s += " WHERE ("
s += " id_screen = " + id_screen
s += ")"
s += " ORDER BY i_order"
try:
db_cursor.execute(s)
return db_cursor
except psycopg2.Error as e:
t_msg = "SQL error: " + e + "/n SQL: " + s
return render_template("error.html", t_msg = t_msg)

def__init__(self, i_width, i_height, t_title, db_cursor):
super().__init__(width, height, title, resizable=false)
self.set_location(100, 100)

# Give our window a background color.

self.player_x = 100
self.player_y = 200
self.player_speed = 250

self.right = false
self.left = false
self.up = false
self.down = false

# Initialize a spritelist to track objects like walls.
# This type of object only stops player motion.

# Initialize a spritelist to track monsters/enemies.
# These objects cause damage to i_hit_points.

# Initialize a spritelist to track powerups.
# These objects give points to the player when a collision occurs.

# Get data from the database into the 3 lists above.
i = 0
for each db_row in db_cursor:
id_screen = db_row.fetch("id")
t_obj_name.append(db_row.fetch("t_obj_name"))
t_obj_type.append(db_row.fetch("t_obj_type"))
t_obj_img_URL = db_row.fetch("t_obj_img_URL")
i_y = db_row.fetch("i_y")
i_x = db_row.fetch("i_x")
t_properties.append(db_row.fetch("t_properties"))
t_color_hit.append(db_row.fetch("t_color_hit"))
# Notice the slightly different syntax here:
#   Instead of placing the value from the database straight into our array via append,
#   we are setting each t_hit_sound item (matched to corresponding object)
#   to be an actual sound object to be played later in our code below.
t_hit_action.append(db_row.fetch("t_hit_action"))
b_hit_possible.append(db_row.fetch("b_hit_possible"))
b_hit_destroys_it.append(db_row.fetch("b_hit_destroys_it"))
b_hit_awards.append(db_row.fetch("b_hit_awards"))
n_hit_awards.append(db_row.fetch("n_hit_awards"))
n_hit_damage.append(db_row.fetch("n_hit_damage"))
# draw the current sprite in db_row
if t_object_type == "obstacle":
# add current obstacle to growing list of Sprites (SpriteList)
self.ListSpriteObjects.append(self.SpriteObject)
elif t_object_type == "enemy":
# add current enemy (sprite) to growing list of Sprites (SpriteList)
self.SpriteEnemies.append(self.SpriteObject)
elif t_object_type == "powerup":
# add current PowerUp to growing list of Sprites (SpriteList)
self.SpritePowerUps.append(self.SpriteObject)
elif t_object_type == "Player":
# increment the counter
i += 1

def enemyMovement():
# Iterate through enemy sprites.
# In this case, there are only 2 enemies but we designed this so
# you can add as many as you want to add to the database.
# THEN we give them a random direction out of eight
#   possible directions.
# FINALLY we add our new-for-this-part "intelligent" direction to
#   the random one.
for currentSprite in self.ListSpriteEnemies:
x = currentSprite.position
y = currentSprite.position

# Random movement
direction = random.randint(1, 8)
if direction == 1:
y += 2
if direction == 2:
x += 2
y += 2
if direction == 3:
x += 2
if direction == 4:
x += 2
y -= 2
if direction == 5:
y -= 2
if direction == 6:
y -= 2
x -= 2
if direction == 7:
x -= 2
if direction == 8:
x -= 2
y += 2

# NEW "intelligent" movement.
if player_y > y:
y += 2
if player_x > x:
x += 2
if player_y < y:
y -= 2
if player_x < x:
x -= 2

# Set the current monster's location on screen.
currentSprite.set_position(x, y)

def on_draw(self):
self.SpritePlayer.draw()
self.ListSpriteObjects.draw()
self.ListSpriteEnemies.draw()
self.ListSpritePowerUps.draw()

def on_update(self, delta_time):
# Delta_time is last time the
#   same function was used; We use this
#   to scale movement speed with speed of processing.
if self.right = true:
self.player_x += self.player_speed * delta_time
if self.left = true:
self.player_x -= self.player_speed * delta_time
if self.up = true:
self.player_y += self.player_speed * delta_time
if self.down = true:
self.player_y -= self.player_speed * delta_time

# Set a new location based on the player's x and y coordinates:
self.SpritePlayer.set_position(self.player_x, self.player_y)

# Move all enemy Sprites.
enemyMovement()

# Update Sprite Lists:
self.ListSpriteObjects.update()
self.ListSpriteEnemies.update()
self.ListSpritePowerUps.update()

# Did the user hit a monster?
i = 0
for SpriteEnemy in self.ListSpriteEnemies:
if b_collision == true:
i_enemy_hit = i
i_hit_points -= n_hit_damage[i_enemy_hit]
# Graphical changes (like explosion or something) code
#   to show crash will go here in later lesson.
# NEW:

if i_hit_points < 1:
i_lives -= 1
if i_lives < 1:
# Dead - Next part we will build code to handle this.
# For now, the player lives forever.
i_hit_points = 100
i +=1

# Did the user run into a power-up?
i = 0
for SpritePowerUp in self.ListSpritePowerUps:
if b_collision == true:
i_pu_hit = i
i_points += n_hit_awards[i_pu_hit]
# Graphics and code to show
#   powerup hit will go here.
# NEW:
i +=1

# Did the user collide with another type of obstacle?
i = 0
for SpritePowerUp in self.ListSpritePowerUps:
if b_collision == true:
# half player movement
self.right = false
self.left = false
self.up = false
self.down = false
# Graphics code to show object collision
#   here in a future part of this lesson.
# NEW:
# increment the counter.
i += 1

def on_key_press(self, symbol, modifiers):
# When a key is pressed:
#   Tracking only the four arrow keys
#   NOTE: We are careful to NOT use elif here
#     because we want to allow diagonal movement.
self.right = true
self.left = true
self.up = true
self.down = true

def on_key_release(self, symbol, modifiers):
# When a key is released:
self.right = false
self.left = false
self.up = false
self.down = false

Def main():
# Primary module
getScreenFromDB()
db_cursor = getObjectsFromDB()
gameWindow(i_width, i_height, t_title, db_cursor)
enemyMovement()

## Conclusion

In this part 7, we continued building a game with Python and Postgres with sound added, as part of a multi-part bunch of lessons where the final result will be a basic 2D graphical top-view game; think Pac Man. We are using Python’s Arcade library for gaming-type features. We are using Python’s “Arcade” library for its gaming-related functions and methods. We used PostgreSQL to read and write screenS and objects, including player, enemies, obstacles, and power-ups. In this lesson we will add sound to make the game more interesting. In future lessons we will add various graphics, a “save game” feature, multi-player, and a screen editor.

Rate     ## Pilot the ObjectRocket Platform Free!

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

## 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.