Game Programming using Python & Pyglet – Part 1

TL;DR: Python is a great programming language that shines in readability and conciseness. It can be interesting to build a video game in Python. This is the first part of a tutorial series in game programming in Python. We will be setting up Python, Pyglet and PyCharm, as well as creating a very simple Pyglet application.  

Python is a great programming language. It’s a fantastic starting point for beginner programmers, as well as a great tool for experienced developers. What initially drew me to Python was its concise readability. The fact that Python penalizes you for not intending your code properly appeases my neat code obsession. After using Python for a while, I wondered why there weren’t much popular game or graphics programming being done in it. Perhaps the most popular graphics and game programming library for Python seems to be the aging PyGame. Next, there’s a library called Kivy which is geared towards UI related development. Finally, I stumbled across a lesser known library called Pyglet. According to forums and postings, Pyglet is “more pythonic” than the old PyGame, but is definitely lacking in exposure.

So why try building a game in Python? After doing some Google Trends searches, it’s clear that Python is overshadowed by other game libraries and frameworks – notably the elephant in the room – Unity.

So why Python and Pyglet? Well this is my blog and I am the overlord. Also I like Python and building a game (a simple 2D shooter perhaps) will be tons of fun and can lead into some further exploration of a decent language. Be warned though: this is my first tutorial series. Things may change, and be updated as I go along, but I will try to continue by posting each part.

Let’s Start

For this tutorial we will be making a simple application that consists of a window with some balls bouncing around. Nothing fancy. If you click on the screen, a ball will be added with a random speed at the location of the mouse.

First of all you would need to have Python installed on your computer. I will be using Python 3. It should not matter if you’re using Python 2 or 3 – there may be some slight syntax changes here and there.

 

Installing Python on Windows

Download and install the latest Python 3 from here:

https://www.python.org/downloads/

I installed Python to C:\Python3 for easy access. Next you will need to add the following paths to your Environment variables.

C:\Python3;C:\Python3\Scripts

Finally, you can test by opening a command prompt window and trying the following:

python –version

The version of Python you installed will be outputted. Also, while we’re at it, we can test pip:

pip –version

What is pip?
Pip is a command tool for installing and managing Python packages. 

Using pip, we can install Pyglet with the following command:

pip install pyglet

 

The IDE I will be using is PyCharm Community edition. This is probably the best thing to write Python code in at the moment. Download PyCharm here:

https://www.jetbrains.com/pycharm/download/

New Project

Start by creating a new project in PyCharm. I called mine PygletGame (this can change to something more exciting sounding when we get some stuff happening in our game). For now, I created the following directories in the project explorer. This can be done by right clicking on the main directory in the explorer panel on the left, and then selecting New  > Directory.

Assets will hold our images and animations, entities will have our game objects, and system will contain any core code. You will notice that in each directory I also created an __init__.py file. These Python files do not contain any code in them for now.

What is __init__.py? 
These files are usually used to mark directories on the disk as Python package directories. It allows for importing Python files and libraries from these directories. 

 

Small Start

So for our first tutorial, we will be doing something really simple. Just a screen with some bouncing balls.

Let’s get lay down some design.

There. We’ll have a base component object. Anything in the game could be a component. Our Ball class inherits Component. We also have a main file that will have a list of Ball objects. For now, don’t think much of the design. Let’s just get something going on the screen. We can revisit the design in later parts. You can create a component.py file in our system directory, a ball.py file in our entities directory, and the main.py file in our root directory. Additionally, create a config.py file in our root directory. This will be used to store any configurations we need like screen width and height.

Following this, I’m just gonna drop the rest of the code and explain each class in detail. Btw, you can view all completed code here:

https://github.com/keshavbahadoor/PygletGame

let’s have a look at our Component class.

In Python, we need to import the abc module so that we can create an abstract class. This allows a class that can be derived from, but cannot be instantiated. This means that in our game we cannot create a Component object. However, we can create a derived component, such as a Ball or a Player.

Our Component class is currently just a holder of variables that describes an object in the game – its x and y position, its width and height, and if the object is active or not. We also have two abstract methods, update_self, and draw_self. Objects in the game will use these for updating logic (position, calculations, etc.) and to render any representational graphics.

What is **kwargs? 
In Python, kwargs is used to allow the passing of any amount of arguments to a function. Think of it as a dictionary structure that you’re adding to via the method or function call. We can then retrieve values from kwargs using their keys or keywords. Hence the name kwargs, or keyword arguments. 

What’s that @ thing?
You may have noticed that these methods contain strange looking ‘@’ symbols on top of them. These are called Python decorators. They allow stuff to dynamically alter the functionality of a function, method or class. In this case, the abc module will dynamically alter the update_self and draw_self methods to be abstract methods.

Pyglet Coordinate System 

In Pyglet, on screen coordinates of the x axis increase going from left to right, while y axis increase going from the bottom to the top. This also applies to any object such as images or sprites in the game. The bottom left of the image will be the zero point.

Moving on, let’s have a look at our Ball class.

As we can see, our Ball class extends our Component class. Our constructor calls super, which is our parent Component class. We then define some other instance variables that our Ball objects will need. Pyglet contains functions and helpers for loading images, as well as creating and using sprite objects.

For this sample, I simply googled a ball image and used a random one that I found. You can get the same one I used from the github repository. Note that the slashes in the path ‘assets\\ball.png’ may change if you’re using Linux. I haven’t tested this on Linux. (If you’re using Linux, please comment and let me know! ).

To create the sprite object, we pass the image object as well as the x and y coordinates of the containing Ball object.

We would like our Ball to move around the screen. It should change direction if it hits any edge of the screen so that it continues to move within our view. To have the ball behave like this, we can update the coordinate position of the sprite instance.

In the code segment above, we simply add the speed value to our Ball x and y position coordinates. Our x_direction and y_direction values should only be a positive or negative 1. For example, changing x_direction from a 1 to -1 results in the speed value being subtracted rather than added, hence changing the direction of the object. Finally, we update our sprite instance using set_position(..).

After this, we can calculate when to change the direction of the ball below.

Generally, these statements say the following.

  • If the ball’s x coordinate is less than 0 (the left edge of the screen), then we invert x_direction.
  • If the rightmost x coordinate of the ball is greater than the width of the screen, then we invert x_direction.
  • If the ball’s y coordinate is less than 0 (the bottom edge of the screen), then we invert y_direction.
  • If the uppermost y coordinate of the ball is greater than the height of the screen, then we invert y_direction.

We need use the ball’s width to check that the right edge of the ball has passed the right screen edge. Similarly, we need to use the ball’s height to check that the top edge of the ball has passed the top screen edge. If we did not do this, our ball will seem to pass out of our screen before changing direction.

One more thing to note is that we import our config file with our window width and height settings. The following is the contents of the config file:

Finally – and we’re nearly there – let’s have a look at our main.py class.

Right. It looks like a lot is happening here. This file basically a script and not a class. Let’s break it down.

Pyglet lets us create a window object. This gives us a handle to our screen where we can draw things to. We pass our predefined window width and height to the constructor of the window object.

In our first app, we would want a few balls moving around the screen. For this, we have a list to hold any instantiated Ball objects.

Each of these ball objects would need to be drawn to the screen, and updated. This is handled in the draw() and update(…) functions. Both functions iterate through the ball_objects list and call the appropriate functions. We use the isinstance(…) function to check if the current object in the list is a subclass of Component.

Pyglet exposes mouse events, such as press, release, drag, etc.  We can use this for letting our application know when and where to create a new Ball object.

The on_mouse_press(…) function utilizes Pyglet window.event decorator to enable this. When the mouse is clicked on screen, we simply append our ball_objects list with a new Ball object. When creating the new Ball object, we specify the x and y coordinates of the mouse click, as well as a random integer for speed. Having each Ball object move at a randomized speed makes our application more interesting.

main.py contains a main() function. This contains an inner function that is decorated with Pyglet’s window.event. The on_draw() function is called each time the window needs to be redrawn. This is where any rendering to the screen should be done in Pyglet. For this, we simply call our draw() function discussed earlier.

Next, we use Pyglet to set a scheduled interval and pass our update() function.  We also define how often we should update. In this case, our update() method will be called every 1/120 seconds.

Finally, the last command runs our Pyglet application.

If you have been following you should have a blank screen. We can add a Ball by clicking anywhere inside the screen. The ball will move and appear to bounce around the window.

We’ll stop here for now. You can try adding a background Component. Let’s say we want a space scene for our balls. In our next tutorial, we will deal with input and movement, and hopefully have something that resembles more of a game. This is my first tutorial, and I have some pretty cool stuff planned ahead. Feel free to leave any comments 😀