Game Python Postgres and Player Login

Introduction

In this sub-lesson, we continue building a game with Python and Postgres with Player Login as part 10 of a multi-lesson series of parts where the result will be a top-down graphical game, where the purpose is for the player to collide with powerups while avoiding monsters that move toward you. We used the Arcade framework for Python due to its many helpful game-related features. We chose Postgres for reading and writing the player, monsters, obstacles, sounds, and power-ups, as well as saving and loading games. In this lesson we will also use Postgres to give registered players (see last lesson) an opportunity to login, using their email address and password. In future articles we will add multi-player capability and a screen editor.

Prerequisites

See part 1 through 9, where we learned how to draw a screen, create PostgreSQL tables for saving and reading screen data and Sprites, read the keyboard to control player movement, added random movements to the monsters, collision detection, intelligent player tracking for the monsters, sound effects, saving the game, load a saved game from Postgres, and create a player id through a registration form. Begin here: Build game with Python and draw a screen.

Overview

We’ll begin by creating a dynamic HTML form where the player can type in their email address and password. Then we will write a Python Flask application using the Request and Render_template functions to show the user that Flask template for the purpose of retrieving the email address and password submitted. Finally, we’ll store the hashed password in our PostgreSQL tbl_players.

Since we went over how request and render_template work in the last lesson, we’ll skim over the functions briefly here.

Flask Request Syntax

1
value = request.form.get(field, default val) # post, which is POST in HTML forms.

Flask Request Example

1
2
t_value_1 = request.form.get("t_value_1", "")
t_value_2 = request.form.get("t_value_2", "")

Flask Render_Template Example

1
return render_template("a_page.html", t_msg = "Some data to show.")

HASHLIB Syntax

1
2
    t_after_hash = hashlib.sha3_512(t_input.encode())
    t_player_password = t_after_hash.hexdigest()

Flask HTML template

Below is the HTML for a login screen. This will display nearly identical on all web browsers, including Chrome, Edge, Safari, and Firefox. Name this file “login.html” and save it in a directory called “templates”:

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
<html>
  <head>
    <link rel="shortcut icon" href="favicon.ico" />
    <title>Dot Munch Game - Player Login</title>
  </head>
  <body>
    <!-- t_msg is part of why we call this page a template -->
    <!-- It is part of this page's being dynamic; the server can fill -->
    <!-- in data at the place where you see {{t_msg}} when we used -->
    <!-- render_template("login.html", t_msg = "A message to show in the page") -->
    <h1>{{t_msg}}</h1>
    <div>
      <!-- Build a form to process user input. -->
      <!-- "method=post" sends the data as a post type instead of a querystring get. -->
      <form
       id="frmLogin"
       name="frmLogin"
       action=""
       method="post"
       onsubmit="return true;"
     >
        <!-- Input text box for the user to enter their email address -->
        <!-- Input has a 'name' param of 't_player_email'. -->
        <!-- So our request function in Python can use this to get -->
        <!--   data submitted from this field. -->
        <div class="form-row">
          Player: <input type="text" name="t_player_email" />
        </div>

        <div class="form-row">
          Your Password: <input type="text" name="t_player_password" />
        </div>

        <!-- button for the user to submit the data they entered in the form -->
        <div>
          <input type="submit" name="btn_submit_login" value="Login" />
        </div>

        <!-- Close the input form -->
      </form>
    </div>
    <!-- Close the HTML document body -->
  </body>
</html>

Request with Flask

We will now look at Flask’s render_template function to send the player to the dynamic page we built above, followed by retrieving the data submitted by the player using Flask’s request function.

1
2
3
4
5
@app.route("/login", methods=["POST","GET"])
def register():
    return RENDER_TEMPLATE("login.html", t_msg = "Login Here")
    t_player_email = REQUEST.form.get("t_player_email", "")
    t_player_password = REQUEST.form.get("t_player_password", "")

Hash the password

1
2
    t_value_hashed = hashlib.sha3_512(t_player_password.encode())
    t_player_password = t_value_hashed.hexdigest()

Analysis: We begin with the value the registered player put into “t_player_password”, use the hashlib function to hash it, hexdigest it into a hex value, so that next we can compare the resulting hashed value to the value stored in the database.

SELECT with Psycopg2

1
2
3
4
5
6
7
8
9
10
11
s = ""
s += "SELECT"
s += " id"
s += "FROM tbl_players"
s += "WHERE"
s += "("
s += " t_player_email = '(%t_player_email)'"
s += " AND"
s += " t_player_password = '(%t_player_password)'"
s += ")"
db_cursor.execute(s, [t_player_email, t_player_password])

Analysis: Here we wrote a parameterized query with SQL, the two parameters being t_player_email and t_player_password. We are seeking a match in the database for any records equal to BOTH player email and player password.

Full Source Code in Python

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
from flask import Flask
from flask import render_template
from flask import request
import hashlib
import psycopg2

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

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

def login():
    return render_template("login.html", t_msg = "Login get save and load game features.")
    t_player_email = request.form.get("t_player_email", "")
    t_player_password = request.form.get("t_player_password", "")

    # Check to make sure user name was filled in
    if t_player_email == "":
        t_msg = "Empty field: Fill in an email address."
        # Empty field? Send the player back to the dynamic page, with a message
        return render_template("login.html", t_msg = t_msg)
    # Check to make sure password was filled in
    if t_player_password == "":
        t_msg = "Please fill in a password"
        # Empty password field? Send them back to the page with error message.
        return render_template("login.html", t_msg = t_msg)

    # Hash pw entered by the player into encrypted hex values
    #   which is what exists in the database.
    #   This way their real password (unhashed) is never exposed.
    t_value_hashed = hashlib.sha256(t_player_password.encode())
    t_player_password = t_value_hashed.hexdigest()

    s = ""
    s += "SELECT"
    s += " id"
    s += "FROM tbl_players"
    s += "WHERE"
    s += "("
    s += " t_player_email = '(%t_player_email)'"
    s += " AND"
    s += " t_player_password = '(%t_player_password)'"
    s += ")"
    try:
        db_cursor.execute(s, [t_player_email, t_player_password])
        db_row = db_cursor.fetchone()
        # Check to see if a row was returned
        # If not then we set i_rows 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()

    if id_user == 0:
        t_msg = "User not found. Try a different email address or password."
        return render_template("login.html", t_msg = t_msg)

Conclusion

In this article, we continued a multi-part series of lessons to code a game with Python and Postgres with Player Login as part 10. The result will be a top-down graphical game, where the purpose is for the player to make contact with powerups while avoiding enemies that move toward the player. We used the Arcade framework for Python due to its many helpful game-related features. We chose Postgres for reading and writing the player, monsters, obstacles, sounds, and power-ups, as well as saving and loading games. In this lesson we used Postgres to give registered players the ability to sign in using their email address and password. We also used some HTML to build a form for the user to put their email address and passowrd into for login purposes.

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.