Python Arcade Game Login and Postgres

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

Introduction

This is part 12 of a multi-part group of articles that teach how to build a 2D game. In this part 12, we learn how to use Python Arcade for game login and Postgres for saving various values, including score, users, and screens. In this part, we see how to allow registered users to login to the game using PostgreSQL. In the article following this one, we’ll begin to explore using sockets to build multiplayer capability into the game.

Prerequisites

  • Please go through ALL of the source code for the complete and playable game, including the sound and image files we made available for you to download here.

  • Please study beginning with part 1 where we learned: (a) how to initialize and populate a game screen window with data queried from our Postgres database; (b) how to initialize Sprites with images and array those Sprites into Sprite Lists; (c) how to monitor the key press event and move the user around the game window in correspondence with specific key presses we watch for; (d) how to move enemies with semi-intelligence and semi-randomness, affected by the current difficulty level; (e) how to allow the player to fire bullets using the space bar key and bullet movement; (f) how to deal with collisions between Sprites and Sprite Lists; (g) how to add different sound effects, including a song playing in the background; (h) how to keep score and store the Player score in Postgres; (i) how to change game difficulty and enemy speed during game play and displaying that difficulty number on the screen; and (j) creating and using a registration screen for the user to create an account that we will now call upon via building a login screen.

  • To investigate all the functions in the Python Arcade library, here is that documentation. Note that Python Arcade is built on top of the Python Pyglet library.

We’ll start off the show by building a simple login screen with HTML.

Script for login screen

Below is a registration screen built in HTML. This will render the same in most all web browsers. Name this page “game_login.html” and put it in a folder called “templates” off the root of your project folder:

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
<html>
    <head>
        <link rel="shortcut icon" href="favicon.ico">
        <title>Pyngo Skater Game Login Screen</title>
    </head>
<body>
<!-- The "t_login_msg_value" you see below is part of -->
<!-- this page being a "template". Since this page is "dynamic", -->
<!-- the server can fill in at the placeholder of {{t_login_msg_value}} -->
<!-- with the value you sent via -->
<!-- render_template("game_login.html", t_login_msg_value = "String value to be written by the server into the h1 below") -->
<h1>{{t_login_msg_value}}</h1>
<!-- Outer container div OPENING. -->
<div>
    <!-- Set up html form for user login -->
    <!-- method='post' sends the two values back to Python as a post for the Flask request function to acquire. -->
    <form id='frmGameLogin' name='frmGameLogin' method='post' onsubmit='return true;'>
    <!-- Input field for the user to type their email. -->
    <!-- Input has a 'name' parameter of 'txt_user_email'. -->
    <!-- So our request function in Python will use this -->
    <!--   to get data from this field. -->
    <div class="formrow">
    User Name: <input name="txt_user_email" type="text">
    </div>
    <div class="formrow">
    Password: <input name="txt_user_password" type="text">
    </div>
    <!-- button for the user to submit the field values in the form. -->
    <div>
      <input name="btnLoginUser" value='Login to Pyngo Skater' type="submit">
    </div>
    <!-- Close the HTML form. -->
    </form>
<!-- Outer container div CLOSING. -->
</div>
<!-- Close the HTML body. -->
</body>
</html>

The next functionality to understand is how we call that “game_login.html” page – called a “template” – from within the Python script.

Call HTML from Python

Render_Template displays an HTML page in the user’s default web browser. The dyanmic page can even be filled with content we determine by using parameters in the render template function. The server renders the page, filling in the “gaps” with those values sent as parameters and sends the completed HTML to the client. Here’s how it works:

1
2
3
from flask import Flask
from flask import render_template
return render_template("/templates/game_login.html", t_login_msg_value = "Welcome to the Pyngo Skater game! Login here.")

Analysis

  • t_login_msg_value: The value assigned to “t_login_msg_value” above will be forwarded, along with the user, to game_login.html, the template we built above. The page is dynamic, so it can receive and use t_login_msg_value. Note: instead of “t_login_msg_value”, you can call your variable anything you want and you can send more parameters and values, if needed. You can even send arrays, which are called “lists” in Python.

Next, we will write some code to request the two values the user submitted via the HTML template we built above.

Python request from form

We’ll start by using the render_template() function we studied in the last part of this series to send the user to the HTML page created above and then request the data submitted by the prospective player.

1
2
3
4
5
6
7
# Application routing
@app.route("/registration", methods=["POST","GET"])
# Set up a function for login
def login():
    return RENDER_TEMPLATE("game_login.html", t_login_msg_value = "Pyngo Skater Registration")
    txt_user_email = REQUEST.form.get("txt_user_email", "")
    txt_user_password = REQUEST.form.get("txt_user_password", "")

Next we’ll check the username and password they entered against what is in the database to hopefully find a match.

Find user in Postgres

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
s = ""
s += "SELECT"
s += " id"
s += "FROM tbl_game_users"
s += "WHERE"
s += "("
s += " txt_user_email = '(%txt_user_email)'"
s += " AND"
s += " txt_user_password = '(%txt_user_password)'"
s += ")"
db_cursor.execute(s, [txt_user_email, txt_user_password])
db_row = db_cursor.fetchone()
# Check to see if a record was returned
# If not: we set id_user to zero
if db_row == None:
    id_user = 0
else:
    # a row was found!
    id_user = db_row[0]

Analysis: Here we used SQL to build a parameterized query, where the parameters are txt_user_email and txt_user_password, both to be SELECT FROM tbl_game_users in PostgreSQL.

Now that we have explored the functions that might be new for you, let’s look at the full source of these additions to our game.

Full Python Code Listing

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
# Be sure to install the following libraries with PIP
from flask import Flask
from flask import request
from flask import render_template
import psycopg2
import hashlib

# Set up
app = Flask(__name__)
@app.route("/", methods=["POST","GET"])

# Database credentials
t_host = "db host address"
t_port = "5432"
t_dbname = "db name"
t_user = "db user name"
t_pw = "db user password"
data_connection = psycopg2.connect(host=t_host, port=t_port, dbname=t_dbname, user=t_user, password=t_pw)
data_cursor = data_connection.cursor()

def login():
    return render_template("game_login.html", t_login_msg_value = "Register to get save game capability")
    txt_user_email = request.form.get("txt_user_email", "")
    txt_user_password = request.form.get("txt_user_password", "")

    # Make sure user email field has a non-empty value.
    if txt_user_email == "":
        t_login_msg_value = "Email field was left empty."
        # Send player back to the dynamic html template with the above message.
        return render_template("game_login.html", t_login_msg_value = t_login_msg_value)
    # Make sure user entered a password on the HTML form.
    if txt_user_password == "":
        t_login_msg_value = "Please create a unique password."
        # Send player back to the HTML form with the above message.
        return render_template("game_login.html", t_login_msg_value = t_login_msg_value)

    # Encrypt the password the user submitted to
    # check against the encrypted one in the database.
    t_value_hashed = hashlib.sha256(txt_user_password.encode())
    txt_user_password = t_value_hashed.hexdigest()
    # Create a query with parameters.
    s = ""
    s += "SELECT"
    s += " id"
    s += "FROM tbl_game_users"
    s += "WHERE"
    s += "("
    s += " txt_user_email = '(%txt_user_email)'"
    s += " AND"
    s += " txt_user_password = '(%txt_user_password)'"
    s += ")"
    # Handle potential errors and send error message with SQL to the user.
    try:
        db_cursor.execute(s, [txt_user_email, txt_user_password])
        db_row = db_cursor.fetchone()
        # Check to see if a row was returned
        # If not then we set the user id to zero.
        if db_row == None:
            id_user = 0
        else:
            # a row was found!
            id_user = db_row[0]
    except psycopg2.Error as e:
        t_msg = "SQL error: " + e + "/n SQL: " + s
        return render_template("login.html", t_msg = t_msg)
    db_cursor.close()
    # Check user id to see if we need to send the user back to the form.
    if id_user == 0:
        t_msg = "Your account using those credentials was not found. Please try different email address and/or password."
        return render_template("game_login.html", t_msg = t_msg)

Conclusion

In this part 12 of a multi-part set of articles where we learn how to build a 2D videogame, we learned how to use Python’s Arcade library for game login and Postgres for checking the user’s login request values against what exists in the database. In the articles following this one, we will begin exploring online multiplayer additions to the game using the Python socket framework!

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.