It's mid-May now, and the Spring semester is over at my college.
This semester was definitely the most difficult of my academic career -- and that's coming from someone who has spent a lot of time in college. I took three Computer Science courses this semester alongside Calculus and Physics. Though as a teenager my aptitude tests stated I should go into a science discipline, I was always hesitant to take STEM-related courses while earning my first degree.
But this semester I was able to prove to myself that not only could I pass these more difficult classes, but that I could even excel in them. I am very happy about that.
This summer I have an internship as an Application Developer at American Century Investments in Kansas City, Missouri, and I am excited about the opportunity to actually work in a production environment. Given that it is full time, however, I doubt that I will have much time to update this blog.
In case you missed it, it was revealed some time ago that the GCW Zero -- an open source, dedicated gaming handheld -- will come with Pygame compatibility. The handheld will be available for purchase in May of this year. That means all the time you have spent building engines in Pygame for practice will not be a complete waste; you could convert them to fully-functional homebrew games. This also seems to further strengthen the argument for increased use of interpreted languages such as Python and Ruby. I am confident that some day soon Python will be used even in the development of commercial video games.
Update 11/2015: The source files can now be fetched from github.
In a previous blog post, I attempted to give you a general idea of how to implement 2D animation in Python. In that post, however, I did very little explaining of the code. In this short guide I will attempt to explain more thoroughly the process of implementing 2D JRPG-style animation in Python using Pygame so that all the major concepts are covered. 1: A Brief Introduction to 2D Graphics
Most 2D
animation consists of the following components:
Moving
a sprite across the screen (moving its x-y coordinates on the screen)
Cycling
through a series of animation frames depending on which direction
the figure is moving
The
first step is very easy. Most tutorials you find on the internet
relating to the topic of ‘Pygame animation’ cover this point. In
order to move the character across the screen, you can simply utilize
the built-in features of Pygame’s sprite.Sprite class, namely the
.x and .y values, to move the figure. We will cover this later in our
actual code.
The
second point is somewhat more complicated, and it is the core concept
of this tutorial. In order to animate our figure, we need a series of
frames to represent the animation. These frames are usually stored in
sprite sheets and can be found on many websites. If you are reading
this tutorial, chances are you already have a sprite sheet in mind.
If you don’t, just do a Google search. The sprite sheets can have
SNES-style graphics (source):
Or more
modern graphics [click the image for full size] (source):
We will
be using the latter image in this tutorial; you should open the full-sized image and save it as serge_walk.png in the directory where you will be saving all your code. Don't worry, though. Oncewe are done with this tutorial, our little game
engine will be able to use any type of 2D sprite sheet.
Now that
we have our sprite sheet, we need to think about how the animation
will actually work. We will essentially need four states to represent
different directions of movement – left, right, up, and down.
Looking at our sprite sheet above, there are a total 15 frames for each
direction of movement. Before we can even
begin coding, then, we have to get a set of values for each frame:
the x and y values of the upper left point of each frame, the width (in pixels) of each frame, and the height (in pixels) of each frame.
You could store these values either in lists or tuples, but I prefer dictionaries for this purpose because each set of values is stored together and because the hash value becomes very convenient when cycling through animation. We want to start with the left-most frame in each set and move rightward.
Thus, we have these values for the left walking frames:
You can
hardcode these values into your code, but with this many frames it does take up a very large amount of space. And in general,
hardcoding these kinds of values is considered bad practice. Nonetheless, you can see an example of hardcoding these values into the class in my previous guide.
A better
idea would be to save these values in separate files and parse them
at runtime. There are various ways to do this, but the easiest is
simply to use Pickle. In order to do this, from the console navigate to whatever directory you want to save your files in -- it should be the same directory where the image is stored and where you intend to write all your code --then type:
Continue the process until you have saved all the frame values listed previously into rs.dat (right frames), us.dat (up frames), and ds.dat (down frames). We now have four files that store all our frame data, and that means we are also ready to start coding.
2. Writing the Code
We could from this point quite easily create our own class for our character, but that would require some unnecessary work. The easiest way to implement our animation is to use the built-in pygame.sprite.Sprite class. Let's create a new file named player.py in which we will save our player class data, and enter the following code (see the comments for explanations):
Now we have a class that will allow us to animate our character. The next step is simply to create a player object and start our main loop, both of which are very simple to do. In the same directory as your other files, create main.py and enter the following code:
If you run your code, you should get the following output:
There are obviously a number of ways this could can be improved. For instance, diagonal movement could be added very easily. But this guide has hopefully given you a brief introduction to animated graphics using Python and Pygame. If you have any questions, please feel free to ask. Happy coding!
My quick guide on how to implement 2D sprite animation in Python/Pygame seems to be getting a steady stream of hits. For this reason, I am currently working on improving the quality of the guide and expanding my explanations.
I am also working on improving the engine itself. First, I want to remove the hard-coded pixel dimensions for the sprite frames and simply have the dimensions instead computed.
Secondly, I want to improve the quality of the sprites being used.
Lastly, I want to add some extra features such as basic collision detection.
Because I am busy with work, family, and school, you can probably expect to see the upgraded guide sometime around the end of December or early January.
This entry is now outdated. Please see the updated entry here.
---
Here's a basic example of how to implement 2D animation using Python and Pygame (an SDL wrapper for Python). I am going to be using the following sprite sheet, which is a 2D version of Serge from the game Chrono Cross (created by the user poxy at the chaos-project.com forums).
Looking at the above sprite sheet, the upper-left image will be our base image (frame 1). We will not use column three at all because the animation looks better without it. So we will be cycling through images 1, 2, and 4 in each row.
As for the coding, we are going to create a class called Serge that extends the pygame.sprite.Sprite class. First I'll show you the whole code, then we'll go through it piece by piece.
Now, let's talk about what is actually happening in this code.
Here's a breakdown of the first 14 lines:
Line 3: Our class Serge will extend the pygame.sprite.Sprite class.
Line 4: The position parameter will be used so that we can indicate the sprite's position when we draw it to the screen.
Line 5: We load our sprite sheet and assign it to sheet.
Line 6: We use the set_clip() method in order to display only frame 1 of our sprite sheet.
Line 7: We assign our current image to the clipped area.
Line 8: Create a rect object to correspond to our image.
Line 9: Assign position so that it corresponds to the upper-left pixel of our rect.
Line 10: Assign our current frame to 0; this variable will be used later to cycle through the frames.
Lines 11-14: Create 4 dictionaries to store the pixel coordinates for our walking animation frames.
Lines 16-20:
In order to animate our character, we need to repeatedly cycle through three frames. In lines 16-20 we create a method to handle this.
Lines 22-27:
We create a method to clip the area of each frame. First we have to check whether we are dealing with multiple frames (movement) or a single frame (standing). If the character is moving, the frames are handled by the get_frame() method. If the character is simply standing, the frame is handled directly by Pygame's built-in functions.
Lines 29-52:
Next, update() relies on the previous two methods by passing them the dictionaries (in the case of movement) or single frames and moving the sprite in the correct direction using the built-in pygame.sprite.Sprite rect.x and rect.y values. Then it sets the current image to the appropriate clipped area.
Lines 54-78:
Lastly, we create the method handle_event() to handle keypresses. Depending on what key is pressed, we pass a state (in this case a string) to the update() method which carries out all work described above. update() animates the character and moves him across the screen based on what key is pressed.
We can save this as serge.py. With all that out of the way, our main.py file is very simple.
In line 8 we create an instance of our Serge class called 'player', and position its upper-left pixel at the x-y coordinates (150, 150). We then create a simple main loop, call our event handler (line 19), make a blue background (line 20), and draw 'player' on the screen (line 21). In order to control the animation and movement speed, we set the clock.tick() value to 10.
Output:
If you run from source, the animation will be smoother. With some very basic tweaking and more advanced sprite sheets, you can greatly improve the quality of the animation by adding more frames, and using the code above you could easily add a running option.
Hopefully this gives you a general idea of how to implement sprite animation in Python and Pygame.
(This guide works with Windows, Mac, and Linux, but you will have to be comfortable with the command line.)
1) https://openshift.redhat.com/app/ << Create a free OpenShift account. When prompted, don't create your first OpenShift app at this time, however.
2) https://openshift.redhat.com/community/get-started << Install all required tools for using OpenShift if you don't already have them. (Skip sections 3-5 on the page that deal with creating/configuring your first app. You'll do that below.) In Ubuntu, for example, you'll need to do the following to install the client tools:
4) There is no step four. Following these steps exactly, you've just built and deployed your first Django app in about 10 commands. You can begin customizing the Django example in /django/ and, when you're ready, simply:
$ git commit -am "Comments about your changes" $ git push
Maybe all this 'cloud' stuff isn't so gimmicky after all. And if Google search trends are anything to go by, learning the Django framework is probably a sensible allocation of your time.