Game Python Postgres Draw Sprites
Introduction
In this tutorial, we will continue creating a game with Python and Postgres with draw sprites as part 2 of a multi-part series of lessons where the final result will be a 2D graphical top-down view game. We’ll use Python’s “Arcade” framework for the graphics-related features it has. We are using PostgreSQL to store and retrieve screen data in the database. In this lesson we will access Postgres to get screen data and draw that data as Sprites. In the next lesson, we’ll learn how to move Arcade’s Sprites and for the player icon to be controlled and moved around the game screen. In later parts (future articles in this series), we will address enemies and collision physics in the game and other pieces of what makes an enjoyable Python graphical game, like scoring points and dying.
Prerequisites
See part 1 where we learned how to draw on a screen, create PostgreSQL tables for storing screen data and screen objects, and pull data from those tables for display on a game screen: Create game with Python and Postgres Part 1. For this lesson we will be using much of what we learned in part 1 but not all. One change will be that instead of using draw commands for objects, we’ll be loading objects in from Postgres and placed into Sprites instead of drawn.
Images built in to Arcade
This is a note about images we could use in this game for Sprites called “resources”. Resources are sounds and images built into Arcade that we can use to build without figuring out how to copy those kind of files into our projects.
Any file load that starts with :resource: will attempt to load that file from the library resources instead of the project directory. [Learn about Arcade Resources here] (http://arcade.academy/resources.html).
That said, we are going to load our objects from our own png image files.
Create a Sprite
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 | # Load and position a screen and player sprite import arcade # Set up variables for screen dimensions window_width = 1280 window_height = 720 # Open the screen. Set title and size arcade.open_window(window_width, window_height, "Drawing with Python") # Set the background color to black # For a color list see http://arcade.academy/arcade.color.html arcade.set_background_color(arcade.color.BLACK) # Turn the render process on. Required before we use drawing commands arcade.start_render() # Create a sprite arcade.sprite1 = arcade.Sprite("sprites/player.png") # Find middle of screen # Divide window height and width by 2 to get center of window mid_x = window_width / 2 mid_y = window_height / 2 # Change sprite position # Create variables to keep track of player x and y coordinates player_x = mid_x Player_y = mid_y # Use the set_position function to change position of our Sprite arcade.sprite1.set_position(player_x, player_y) # Keep the window up until the user clicks close arcade.run() |
Get screen from PostgreSQL
Now we’ll retrieve screen data, which is objects and their locations in 2D space, from two tables. We’ll start by creating the tables. Why two? One table (“tbl_screens”) will have a row per screen, while the second table (“tbl_screens_objects”) will store all the objects and use id_screen to point back to the id field in tbl_screens.
PostgreSQL tables that store screens
Here is tbl_screens with one row of sample data to represent screen 1 of the game:
id | t_title | t_color | i_width | i_height |
---|---|---|---|---|
1 | Screen 1 | BLACK | 1280 | 720 |
Here is tbl_screens_objects which contains our Sprites. This table relates to the above table via the id and id_screen fields.
id | id_screen | t_object_name | t_object_type | t_object_image_URL |
---|---|---|---|---|
1 | 1 | Player | sprite | player.png |
2 | 1 | Wall | sprite | wall.png |
3 | 1 | Tree | sprite | tree.png |
4 | 1 | Powerup | sprite | powerup.png |
5 | 1 | Enemy1 | sprite | enemy1.png |
6 | 1 | Enemy2 | sprite | enemy2.png |
NOTE: For tbl_screens_objects, for now, we are only showing the relevant fields for setting up the sprites, leaving out our columns that deal with collisions and sounds.
Query PostgreSQL for screen data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # First we get a screen ID and title from tbl_screens from FIRST screen s = "" s += "SELECT TOP 1" s += " id" s += ", t_title" s += ", t_color" s += ", i_width" s += ", i_height" s += " FROM tbl_screens" s += " ORDER BY i_order" try: db_cursor.execute(s) id_screen = db_cursor.fetch("id") t_title = db_cursor.fetch("t_title") i_width = db_cursor.fetch("i_width") i_height = db_cursor.fetch("i_height") t_color = db_cursor.fetch("t_color") except psycopg2.Error as e: t_message = "Database error: " + e + "/n SQL: " + s return render_template("error.html", t_message = t_message) db_cursor.close |
Analysis: Read window/screen data from PostgreSQL, including screen id, title, dimensions, and color.
Query PostgreSQL for objects data
Now that we have the data we need for the screen, we can query tbl_screens_objects to get all the objects associated with that specific screen.
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 | s = "" s += "SELECT" s += " id" s += ", t_object_name" s += ", t_object_type" s += ", t_object_image_URL" s += ", i_x" s += ", i_y" s += ", i_width" s += ", i_height" s += ", i_radius" s += ", t_color_fill" s += ", t_color_border" s += ", t_color_collision" s += ", t_properties" s += ", t_collision_sound" s += ", t_collision_action" s += ", b_collision_possible" s += ", b_collision_destroys_it" s += ", b_collision_awards" s += ", n_collision_awards" s += ", n_collision_damage" s += " FROM tbl_screens_objects" s += " WHERE (" s += " id_screen = " + id_screen s += ")" s += " ORDER BY i_order" try: db_cursor.execute(s) except psycopg2.Error as e: t_message = "Database error: " + e + "/n SQL: " + s return render_template("error.html", t_message = t_message) |
Analysis: The query above retrieves all object data for a specific screen.
Draw Sprites from recordset
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 | import arcade # First we open a window with arcade window_width = i_width # from database window_height = i_height # from database # Open the window. Set title and screen size arcade.open_window(window_width, window_height, t_title) # Set the bkg color to t_color from tbl_screens arcade.set_background_color(arcade.color.t_color) player_x = 100 player_y = 200 # Create first sprite, which is our player Player = arcade.Sprite(t_object_image_URL, center_x=player_x, center_y=player_y) # initialize sprite list arcade.sprite_list = arcade.SpriteList() # Now iterate through each record (row) # and draw the object to the screen for each db_row in db_cursor: # get data from database id_screen = db_row.fetch("id") t_object_name = db_row.fetch("t_object_name") t_object_type = db_row.fetch("t_object_type") t_object_image_URL = db_row.fetch("t_object_image_URL") i_x = db_row.fetch("i_x") i_y = db_row.fetch("i_y") i_width = db_row.fetch("i_width") i_height = db_row.fetch("i_height") i_radius = db_row.fetch("i_radius") t_color_fill = db_row.fetch("t_color_fill") t_color_border = db_row.fetch("t_color_border") t_color_collision = db_row.fetch("t_color_collision") t_properties = db_row.fetch("t_properties") t_collision_sound = db_row.fetch("t_collision_sound") t_collision_action = db_row.fetch("t_collision_action") b_collision_possible = db_row.fetch("b_collision_possible") b_collision_destroys_it = db_row.fetch("b_collision_destroys_it") b_collision_awards = db_row.fetch("b_collision_awards") n_collision_awards = db_row.fetch("n_collision_awards") n_collision_damage = db_row.fetch("n_collision_damage") # draw each object in db_cursor to screen # ignoring if player because we already created player as sprite1 above. # This assumes we didn't filter out "player" by changing our SQL WHERE clause. if t_object_type == "sprite" and t_object_name != "Player": self.SpriteObstacle = arcade.Sprite(t_object_image_URL, i_x, i_y) self.sprite_list.append(self.SpriteObstacle) elif t_object_type == "sprite" and t_object_name == "Player": self.SpritePlayer = arcade.Sprite(t_object_image_URL, i_x, i_y) db_cursor.close self.sprite_list.update() self.sprite_list.draw() # Keep the window alive until the user clicks close arcade.run() |
Conclusion
In this tutorial, we continued building a game with Python and Postgres with draw sprites as part 2 of a multi-part series of lessons where the final result will be a 2D graphical game. We are using Python’s “Arcade” library for the graphics-related functions. We are using PostgreSQL to store and retrieve screen data so we can have potentially infinite screens in our game. In this lesson we used Postgres to get screen data and draw that data as Sprites. In the next lesson, we’ll learn how to move the player around the game screen. In later parts (future articles in this series), we will address enemies and collision physics in the game and other pieces of what makes an enjoyable Python graphical game.
Pilot the ObjectRocket Platform Free!
Try Fully-Managed CockroachDB, Elasticsearch, MongoDB, PostgreSQL (Beta) or Redis.
Get Started