As a recap, in some previous blog posts we set up the Pi, and experimented a little with graphics.
In this fourth mini project, the aim is to play a little more with graphics, this time to create part of a game. No prior experience is needed in programming or gaming to follow this project and to make your own customizations. The code here can be modified and used whenever you want animated objects on a screen and movement.
The entire game won’t be built, but enough to show how to move and animate a games character on a stage.
To show how little effort is needed with modern computing, the animation of a key Street Fighter character can be achieved in a couple of dozen lines of code. Bearing in mind that the game series was easily responsible for $10bn of revenue if not more, then if we could go back in time then each line of code is worth millions!
The 30-second video here shows the result of the few lines of code on the pi:
What is Street Fighter?
If you’ve been asleep for the past two decades : ) Street Fighter is a classic video game, seen in arcades, PCs and games consoles. It was extremely popular and the later Street Fighter 2 made the Super Nintendo the success that it was. The game was highly addictive and successful because it had characters with their own unique looks, skills and mannerisms, great music and speech, easy to get into (you just fight!) but with more advanced skills to learn and perform over time. It resulted in many sequels, toys and movies.
For the purposes of learning computer programming this blog post will reuse some graphics from Street Fighter. They are downloadable from spriters-resource.com.
For educational purposes, a few of the images from that website have been used, I believe this can be considered fair use since we’re not re-creating the entire game. Just enough to demonstrate animations for video games, using a popular game for familiarity, to set the context.
Sprites and 2D Games
There are many types of games and one straightforward, low-processing-effort way of games creation is to rely on square or rectangular grids of pixels and construct your two-dimensional games characters and objects inside there. Often games consoles and graphics processors have dedicated circuitry to accelerate the placement of such items on the screen. Some more modern types of games can have 3D representations of objects.
These grids of pixels with the characters or objects are known as sprites. It is far quicker to draw small sprites than update the entire large screen, so using sprites can make games run fast.
In the case of this project, the aim will be to animate a character from Street Fighter, Ken. From the website mentioned earlier, a .gif file was downloaded that contained all the animation steps that this character can take in the actual game. (Don’t download the image reproduced below, it is a low-res copy; use the one from the website link earlier). For this project, the four frames of animation that are circled in yellow are used; these represent the ‘idle’ movement of Ken, when he is ready to fight and he is just getting ready to kick or punch. In the video game, these four frames of animation are repeated while he waits to attack or to be attacked.
Some image manipulation software is needed to cut the larger image into the four desired frames which will become the sprite for Ken idling on the spot. Something like Microsoft Paint could be used, or some open source software. For those serious about creating games, a low-cost tool popular among 2D graphics artists is called Pro Motion by Jan Zimmermann.
Sprites would be an ugly solution if they had to have a rectangular colored block (see the first Ken in the image below). Sprites are useful when they can be used in front of a background image as shown with the second Ken in the image below.
This trick is achieved by assigning one color in the image file to be a ‘transparent color’. Whenever the computer sees pixels in that color, it will skip it and thus the background will continue to be visible there. Not all image formats support the capability of containing a transparent color. If you’re saving sprites, use GIF or PNG format (I used .gif format for this project).
Show me the Code
The rest of this blog post describes how the code works, detailing what occurs on the important lines in the code files. It describes what folders would be created if you were doing this from scratch, and what content would be in the files.
However, to save effort, there is no need to type it. You can download it directly onto the Pi and then continue reading the blog post.
To do this, log into the Pi and open a terminal (an icon for this is on the top start bar on the Pi desktop, or click on the raspberry at the top-left and select Accessories --> Terminal. Then, in the terminal, type the following:
mkdir development cd development git clone https://github.com/shabaz123/game1.git
This will have resulted in a folder in your home folder (usually /home/pi) called development, and it will contain another folder called game1 (and a nested folder in there called assets) and the entire code and graphics files for this project will have automatically be downloaded. To run the code, now type:
cd game1 chmod 755 sf.py ./sf.py
To start working on the game, create a folder on the Pi called (say) game1 (as mentioned above, if you download the code, all this is already done!). In that folder, create another folder called assets and place the .gif files in there. The reason for the sub-folder is just tidiness. Since there are four frames of animation for ken while he is idling, I named the files ken_idle_1.gif and so on.
Next, back in the game folder, create a file called ken.py (again, already done if you download the code!). It is good to be consistent and stick to a naming convention. For filenames I personally try to avoid uppercase characters.
The programming language used here is called Python. Programming languages often have similarities so you’ll see that the code doesn’t look so different to what was seen in the code in the earlier blog posts. One big difference however is the lack of curly brackets for portions of code. Instead, Python uses spaces. The indentation is important with Python.
Here is the code for Ken, this is in the ken.py file:
If we try to examine it, we can see some generic stuff like comments and modules being imported, but then the interesting area would appear to be from line 16 onwards, where it says class Ken. From line 21 it can be seen that the animation frames are loaded from the .gif files in the assets folder. Further below (line 28) there is a value 800, and it is a value that determines how fast the animation is to occur. A large number slows down the animation. The following line after than has some numbers which are related to the sprite size, and the location where it is desired to place Ken. The .gif files are of size 50x90 pixels, and Ken is initially placed at co-ordinate (5,100). The co-ordinates are referenced from the top-left. The origin (0,0) is the top-left part of the screen, and the top-left of Ken’s sprite is placed close to the left side of the screen, and 100 pixels down. In other words, he will be placed in his corner of the fighting area.
There are several lines of code that begin with the text def. These are functions. For example, there is a function called getrect on line 32. It allows anyone calling that function to retrieve the rectangle information (the location on the screen where the sprite is to be placed, and the width and height of the sprite).
The word self is used a lot too. This is because Ken is not a person yet. In the ken.py file Ken is a class or a description of a potential object that could be created, meaning that in theory we can create as many Kens as we wish from it, although we will only create one. Each Ken could have its own position on the screen, and self refers to the reference of any real Ken that is created (it all makes more sense as you see where Ken is instantiated later).
To use this code, somewhere you’d type something like
Until that is executed, real Ken doesn’t exist in computer memory. The computer knows how Ken should look like from the class, and how he should move when he is idling on the spot, but no memory has been used to create a real Ken and store his location. If you wanted to create another Ken, then you could type:
With the current code it would mean that the second Ken would be initially placed in the same location, so you’d then have to move him.
Creating the Scene
The ‘somewhere’ where Ken could be brought to life inside the computer (i.e. instantiated), could be in the same file or in a different file.
It can get really messy having a computer program in just a single file particularly when the code gets large. As a result, one often sees a file called, depending on preference and depending on the computer language, (say) main.c or streetfighter.py and then lots of daughter files. The main file contains the initial code that runs. It calls upon on all the other files as required.
For this project, the main file was called sf.py and the contents are shown here:
If we examine it, one interesting thing is that the very first line looks unusual. The hash and exclamation point (#!) are a special combination that the operating system (e.g. Linux in the case of the Pi – for more information, see some of the earlier Get Started Coding blog posts) can recognize and make life easier for program execution. The first line in this manner is used to specify what program can run the code. In this case, since we’re using the Python programming language, the first line can be used to specify this. To run the code the user can just type
The operating system will automatically examine the first line, and know that the rest of the code will be executed by the software called /usr/bin/python3.
Line 11 shows how the main code can know about the additional files of code. It specifies that the file called ken (the suffix is implied to be .py) contains a class called Ken (for the same of convention, the class names will begin with an uppercase character).
Incidentally the line just above that (line 10) specifies that there is another file called background.py. This file contains a class called Background that will be responsible for creating the (you've guessed it) background. It is not an interesting file, the code is just a few lines and is not shown in this blog post but is of course in the code bundle downloadable for this project and can be viewed if desired.
From line 20 onwards the main function is defined. Line 21 initializes a body of code (also known as a library) called pygame. This library contains many helper functions to place sprites on the screen and all game-related tasks.
Lines 25 to 32 are responsible for drawing the stage background for the game. It uses a graphics file called stage_1.gif for that. Were the fighters to play an additional scene, then a stage_2.gif would also be needed.
Some more terminology is used in this part of the code that might not make immediate sense, but is related to the games engine (pygame) and to the computer graphics world. The term surface for pygame refers basically to images. It is possible to create a surface variable or object, and place an image (e.g. from a .gif file) on it, and then place it on the screen surface. You could create several surfaces in memory, and choose which one to copy onto the screen surface. The act of copying a surface onto another is called blitting in the games graphics world. In our case we are copying the image identically, but sometimes blitting is done in a way that if there is already something on the target surface, the colour of the source can change or invert. A good example of this is a cursor. Although the cursor is usually white, if the surface is already white then you want the cursor to be black otherwise you’d never see the cursor. If the surface is half white and half (say) red, then you might want the cursor (if it is blitted onto that surface at a position on top of these colors) to be partially black, and (say) partially yellow for good contrast against the red.
The heart of the game control begins from line 40. This a loop that checks to see what button is pressed (the variables btn_left and btn_right on lines 47 and 50 were defined on lines 16 and 17 to be keyboard buttons O and P and are used to move Ken left and right), and redraw Ken. The update function on line 58 is in the ken.py file of course, and it animates the next frame every 800 cycles (if you recall, this was defined in ken.py in line 28).
When a button is pressed, the position of the rectangle for the sprite is adjusted by 1 pixel by calling a function for Ken called movepos (line 49 and 52 of sf.py); the function is in ken.py on line 35. When the sprite is next redrawn, it uses the updated rectangle position.
If you’ve played Street Fighter then you’ll notice that Ken has a walk when he moves. This would be a different animation to the ‘idle’ animation. It is an exercise for the reader to implement this. To achieve it, one way would be to load more than 4 frames of animation in the code in ken.py, and then manipulate the idx variable in such a way that only the frames relevant for ‘idle’ are played out repeatedly when he is idling, and then change the value of idx to be a higher value in the range of the ‘walk’ frames of animation when the left/right keyboard button is pressed.
If you’re keen to try creating games, then hopefully the code here can serve as a basic structure or to provide ideas. The main references are the Python language (Python quick reference; this is for an older version but still extremely useful), and the pygame documentation.
There is also a raspberrypi.org PDF document that teaches pygame, which might be worth examining.
With not much code it is possible to achieve animation very close to the original arcade game, for the character Ken in his idle ‘pre-fight’ position, and accept keyboard input to make the character move.
Sprites are used in thousands of games, so the technique is relevant for other games projects too.
For non-games related applications, sprites could be used to animate (say) the position of a robot sprite on the screen in synchronization with a real-life robot doing it for real.
If you try out the code here or try new things with pygame, it would be great to hear about it, and to see the image or video results!