UPDATE: Here’s the original code for PiPong
In this tutorial we’re going to be remaking the classic game, Pong. To do this, we’ll be using a Python module called Pygame. Pygame is great, because it allows the programmer to create 2D games without having to worry about things such as rendering the graphics in too much detail. The main portion of the code will be the code that makes up the game’s structure and logic.
Pong is an ideal game to introduce the principles behind game development as it is fairly simple, which makes it much easier to understand what’s going on. This also means that it requires less code, making it ideal for those just starting out in programming.
The first step, of course, is to start up our development environment, which is the Geany editor, and create a new Python file using the ‘with template’ option. We only need the first line and the bottom couple of lines – delete the others so you only have the lines shown here:
As usual, we’re going to add some comments to the start of our program to help out anyone (including ourselves) who might end up using it. We wrote the following:
You’ll want to save your file inside a new folder for the project, which we’re cleverly naming PiPong. You should save your file with the name ‘PiPong.py’.
The standard stuff
Pretty much every game in Pygame starts off in a similar way: by importing the required modules and then having a game class with an initialisation method that is called when an instance of the class is created. This initialisation method is where we set everything up. Don’t worry if this doesn’t seem clear at the moment – you’ll see how it works in a moment.
We need to start off by importing some modules after we have written our initial comments. It’s good style to have each import on a separate line, because you can follow the import with a comment explaining what the library is used for. Import the modules as shown below:
After the imports, leave a blank line and then write the line ‘from Pygame.locals import *’. This essentially means that everything is imported from the Pygame locals module.
This enables us to use constants (variables that can’t be changed) from the Pygame module. An example of a constant would be the KEYDOWN event, which is triggered whenever a key is pressed. By importing the constants, we can use them in code as just that, rather than having to refer to them as Pygame.locals. KEYDOWN. This makes our code tidier, and easier to read.
We’re going import the whole Pygame module too, so do that using the code ‘from Pygame import *’. This just saves us having to write ‘Pygame.’ in front of a whole bunch of things.
It’s now time to create our game class. A class is defined very simply using the syntax ‘class PiPong:’. Now that we have a class, it’s time to move onto the initialiser function.
Before we begin
There has been a lot of activity in the Raspberry Pi community recently. As a result of this, there is now a new operating system for the Raspberry Pi named Raspbian. As you might have guessed, this is just a Raspberry Pi-specific version of Debian, which has been used in previous tutorials.
The advantage to Raspbian is that it takes advantage of all of the hardware available on the Raspberry Pi, offering a significant performance increase over the previous Debian images. The disadvantage of the Raspbian distribution is that the current image doesn’t have all of the packages we need for this tutorial by default. A code editor such as Geany is missing (although there are command-line alternatives included).
It doesn’t actually matter if you are still using an old Debian image or not, as the programs we are using will work in exactly the same way. Not to worry though if you are using the new Raspbian image, because all you need to do is enter the command ‘sudo apt-get update’ followed by ‘sudo apt-get install geany python-Pygame’.
If there are any problems with this, then we recommend that you go back to the last Debian 6 image, which you can find by going to the download page.
This tutorial will all be much easier once you understand member variables, so let’s take this opportunity to learn about them.
A variable called ‘self’ is usually passed to every function in a class. The self variable is a reference to a particular instance of the class and allows the programmer to access member variables and methods from that particular instance. This is passed to all instance methods within the class. For example, we make the display size a member variable so that it can be accessed from every function in the class.
The game class initialiser
In the initialisation function of the game class, we will do a number of things, such as initialise the Pygame module, create a clock to manage time and speed in the game, create a window and many more things.
Coding the class initialiser
The first thing you need to do is copy the code from the ‘Member variables’
boxout (page 47), because that’s the start of our initialiser class. The class initialiser function is always defined with the syntax ‘def __init__():’ where any parameters to be passed are put inside the brackets. Note that the lines before and after are made up of two underscores. The next thing to do is initialise Pygame, by calling Pygame.init(). Note that we could just call init() because we have imported the Pygame module, but it looks a bit odd and it’s clearer to be explicit in what we are calling.
We now need to create a clock to manage the time in the game. The clock allows us to specify the number of frames per second the game should run at, among other useful things. A clock is created by creating a new instance of the Pygame.time.Clock class in the following way: self.clock = Pygame. time.Clock(). Another bit of housekeeping we need to do is to set the window title using the syntax: display.set_caption(“Pi Pong”).
For now, the final part of the class initialiser is creating the window, which we do using the syntax: self.display = display.set_mode(self. displaySize). The display size, which we’ve set to 640×480, was set earlier on in the initialisation function. We’ve chosen 640×480 as the resolution for the game as that should be pretty much suitable for everyone. We’ll have to come back to the class initialiser later on, to do things such as creating the background, the bats, ball and so on.
The game loop
Pretty much every game works using a loop – this is a continuous piece of code that keeps repeating itself. A typical game loop may take the following structure: handle any input events update any objects accordingly, draw the objects to the display surface, update the display, wait until it is time for the next frame. Interestingly, if the game doesn’t wait a certain amount of time before looping again, it will hog the CPU by trying to use it all of the time because the loop will start again as soon as it is finished. This is where the clock object we talked about before comes in useful.
Before we start the game loop, it makes sense to go back to the initialiser function of the PiPong class so we can create a background. After the line where the display is created, you need to create an instance of the background class, passing through the display size, by typing ‘self.background = Background(self. displaySize)’. Now we can move on to the game loop, because we’ll actually have something to render on the display.
After the line where you have created the background, we need to make a new function called run, which is where the code for the game loop will go. Leave a blank line and be sure to move the indentation back a level. Define the function like you would any other, passing self through as usual, with the syntax ‘def run(self):’. We then need to start the while loop with ‘while True:’. Using the constant True means that this is an infinite loop and will run until the program exits. The while loop code is self-explanatory, so you should be fine to copy it in.
Understanding co-ordinates and axes is crucial to game development – so let’s take a recap.
The co-ordinate system in 2D game development is usually always the same. The x axis goes from left to right, with the far left value being 0. The y axis goes from bottom to top. However, the highest point at the top has the value 0, which is different to if you were drawing a graph. Co-ordinates are written in the form (x, y). The top-left corner of the screen has the value (0, 0).
The background class
The background class is pretty simple: all it has to do is create a surface, fill it with a green colour and then draw a white line down the middle in proportion to the display size. This means that the code itself is also pretty simple, so we’re only going to explain the less obvious parts.
displaySize is the width component of the display and displaySize is the height component of the display
Here, we are creating a rectangle with x and y co-ordinates (0, 0), which is the top-left corner. We are also passing the width and height following this
Here we are saying, draw the rectangle to the background surface, in the colour white (255,255,255 in RGB colour code)
Blit stands for block image transfer. This function will allow us to render the background surface to the display which is passed in during the game loop, which we’ll get onto in a moment
The first run
We’re now at a stage where we can get some of our first Pygame code running.
Now all we have to do to get this to run is to change the main code from the very start, which is how the program starts. The main code needs to look like this:
if __name__ == ‘__main__’: game = PiPong() game.run()
This code will call the init function of the PiPong class when the new instance is created, and then call the run function to start the game loop. You can press the button with the three cogs on it to run the game. Note that we haven’t handled the quit event yet, so you’ll have to use the red stop button to stop the game.