Adding some flair!
In this section we will look at how you include and manipulate images in Pygame. Good quality visuals can go a long way to making a game engaging and drawing the player in.
Before we begin, let's create a new file (call it images.py) and copy in the template code from the previous section
Once you've saved your file with the template code in it, run the file to make sure you've copied it in ok.
We will also need some images to play with. Create a directory called images in the same directory as your Python file and place these images into this directory. Right click and download these images.
(Right click and "Save image as ...", or similar)
It is possible to access and load the images from anywhere on the system but if you place them in the same location as the Python file it makes things a little easier. It also makes things easier when you want to package up and share your game later on.
Including images is a three step process (though a lot of the time we can skip the second step) :
Let's start by loading our image so that it is ready to use. Place the following lines of code in your main function, near the top like so :
This command will load the image into what is called a surface and save it to a variable called tom.
Here we have loaded the image into a variable within the function that it will be used. This is an ideal location to load the image if it is only going to be used within that function. It keeps things clean and local. If you will be using the image in several areas across several functions however then it may be better to load the image once at the top of the script as a global variable. This will give a slight performance boost as you won't need to keep loading the same image.
The end of the command .convert_alpha() sets your surface to manage colours and transparency in the native format for your operating system. You can leave this off and the conversion will happen when you BLIT the image to the screen (see below) but if you do this then it has to do the conversion every time the screen is updated (30, maybe 60 times a second) which will give a big hit to your game performance.
If you save and run the program you will notice that nothing has yet happened. Our screen is blank. Let's change that. Add in the following line just between filling the window and updating the display :
The blit command does what is called a Bit BLock Transfer and copies the bits from the surface which holds our image (in the above script, held by the variable tom) into the relevant location on the surface which is our actual WINDOW.
If you change the BACKGROUND colour you will also notice that the transparency in the png image has been brought through as well. This is a nice advantage of using PNG over JPEG as the file format for your images as otherwise your game elements will have borders around them which is a bit unsightly.
In the above program you will notice that our character ( Tom ) is a little bit large in our window. There are a few ways we can rectify this. We could for instance make the window larger, or we could open up the image of Tom in our favourite image editor and scale the image down a bit. PyGame offers us a means to transform the image within our code and this is an easier and cleaner way to go about it (especially if you want to scale your image for various reasons within your game or you don't know what size will be ideal yet and just want to tinker).
Using the transform module we can perform a variety of operations on our image :
Although I've talked about an image with the operations above what they are actually processing is a surface (in this case the surface which holds the image). You may apply these operations to any surface however, not just images.
There are other operations available through the transform module as well. I've just introduced the more useful / common ones here but if you do a quick search you can discover more complex transforms available to you.
Let's make Tom a more reasonable size for our window :
If you add the above code in the Processing section of your game loop and run your program you should find that Tom is now half the size he was before.
newSurface = pygame.transform.scale(originalImage, (newWidth, newHeight))
What we've effectively done in the above code is take the image stored in the surface under the variable tom, resize it to be 50 pixels wide and 95 pixels high, then save it back into the original surface, tom. If we wanted to, we could have saved it into a new surface by changing the name of the first variable to something different.
The flip command can be useful if you want the character to look like he's heading in the direction he's moving.
newSurface = pygame.transform.flip(originalImage, Xflip, Yflip) #Xflip and Yflip are both either True or False
Let's start by adding in some code to make Tom move left and right :
Now Tom should be able to move left and right. Next we will create two surfaces, one where Tom is looking to the left and one where Tom is looking to the right :
And now we will add in a bit of code to change the surface to use depending on which direction Tom in going :
And finally, let's change the surface that we blit from tom to the new tomRunning which we have now created.
Just for fun, let's allow Tom to jump as well. This will allow us to tinker with some simple physics.
First off, let's create two new variables to store our current jumping velocity and the jumping strength :
And now we'll add in a condition to set our velocity higher when SPACE is pressed :
Finally, let's adjust Tom's Y coordinates based upon this velocity :
We could have achieve this behaviour with a few if statements to handle moving up and moving down one after the other but doing it this way with a velocity gives us two benefits :
Sometimes you may only want to display part of an image. An example of when this is useful is if you create a single image which contains multiple states of your character or enemy. You can then load the image once and crop it to only show the relevant part of the image.
In PyGame we do this by creating a new surface and BLITing the relevant part of the original surface which holds the image to the new surface.
Let's demonstrate this by creating a simple reaction time game.
Download the following image which is a sprite of our reaction targets.
Here is an annotated version of the image with pixel values marked for your reference:
What we're going to do is randomly pick one of the directions, crop the image to only show that direction on the screen then measure how quickly the player can hit that button.
We'll start by just checking that we can crop the image and show only a single tile.
Let's create a new file (call it reaction.py) and copy in the template code from the previous section.
Now we'll load the image (reaction_sprite.png) and crop it to only show the up arrow tile :
You'll notice that the blit call looks a little bit different this time. We have added an optional argument to define the area from the original image to blit to the WINDOW. We do this by specifying the upper left corner of the area that we want to display followed by it's width and height.
If you change the value of cropY to 150 and the value of cropX to 300 which tile gets displayed now? Tinker with the values and see if you can get the other tiles to display as well.
Now let's put these concepts together into a little game that we can tinker with. We're going to create a simple Left / Right reaction timer game.
Let's create a new file (call it reaction.py) and copy in the template code from the previous section
Once you've saved your file with the template code in it, run the file to make sure you've copied it in ok.
We will also need the image from the above section ( Reaction sprite ). Place this image in your images directory in the same directory as your Python file.
We will start by loading the Reaction Sprite image and setting up a few variables. Place the following code at the top of your main function :
And let's also set up some code to detect when keys have been pressed :
After detecting key presses we then need to process accordingly :
We also have to include some processing to display the right image to the player :
Let's not forget to blit the image to the screen so the user can see it :
And finally, once the ten rounds are up, we should display the score to the player :
We're done! If you save and run your script you should have a basic reaction timer game.
Even though our program doesn't do too much just yet we can still tinker with a few elements to make sure we understand them.
Have a go at the following :
1. Can you improve your images.py script so that another image is shown when Tom jumps?
2. Can you use the drawing functions to create a ground and background for Tom to run around and jump in front of?
3. Can you improve the reaction timer game by getting the images to show up on the screen in random locations instead of always in the middle? Think of any other enhancements you could create as well.