Unit 7 - Graphics and Sound

To move beyond the simplistic shapes offered by drawing circles and rectangles, our programs need the ability to work with bitmapped graphics. Bitmapped graphics can be photos or images created and saved from a drawing program.

But graphics aren't enough. Games need sound too! This chapter shows how to put graphics and sound in your game.

7.1 Drawing Text

To draw text to the screen there are three things that need to be done. First, the program creates a variable that holds information about the font to be used, such as what typeface and how big.

Second, the program creates an image of the text. One way to think of it is that the program carves out a “stamp” with the required letters that is ready to be dipped in ink and stamped on the paper.

The third thing that is done is the program tells where this image of the text should be stamped (or “blit'ed”) to the screen.

Here's an example:

Drawing text on the screen

# Select the font to use, size, bold, italics

font = pygame.font.SysFont('Calibri', 25, True, False)


# Render the text. "True" means anti-aliased* text.

# Black is the color. The variable BLACK was defined

# above as a list of [0, 0, 0]

# Note: This line creates an image of the letters,

# but does not put it on the screen yet.

text = font.render("My text",True,BLACK)


# Put the image of the text on the screen at 250x250

screen.blit(text, [250, 250])

*anti-aliased:In computer graphics, antialiasing is a software technique for diminishing jaggies - stairstep-like lines that should be smooth. Jaggies occur because the output device, the monitor or printer, doesn't have a high enough resolution to represent a smooth line.

Want to print the score to the screen? That is a bit more complex. This does not work:

text = font.render("Score: ", score, True, BLACK)

Why? A program can't just add extra items to font.render like the print statement. Only one string can be sent to the command, therefore the actual value of score needs to be appended to the “Score: ” string. But this doesn't work either:

text = font.render("Score: " + score, True, BLACK)

If score is an integer variable, the computer doesn't know how to add it to a string. You, the programmer, must convert the score to a string. Then add the strings together like this:

text = font.render("Score: " + str(score), True, BLACK)

Now you know how to print the score. If you want to print a timer, that requires print formatting, discussed in a chapter later on.

7.2 Storing the Program in a Folder

The programs we've made so far only involve one file. Now that we are including images and sounds, there are more files that are part of our program. It is easy to get these files mixed up with other programs we are making. The way to keep everything neat and separated out is to put each of these programs into its own folder. Once you have the image saved on your computer you can drag them to your project folder in Pycharm.

7.3 Setting a Background Image

Need to set a background image for your game? Find an image like the image below.

Saturn Image

Any bitmap images used in a game should already be sized for how it should appear on the screen. Don't take a 5000x5000 pixel image from a high-resolution camera and then try to load it into a window only 800x600. Use a graphics program (Online Image Editor or Gimp) and resize/crop the image before using it in your Python program.

Loading an image is a simple process and involves only one line of code. There is a lot going on in that one line of code, so the explanation of the line will be broken into three parts. The first version of the our load command will load a file called saturn_family1.jpg. This file must be located in the same directory that the python program is in, or the computer will not find it:

If you are looking on-line in a web browser, you can usually right-click on an image,and save it onto the computer. Save the image to your desktop then drag it into your Pycharm project.

# Image from http://ProgramArcadeGames

pygame.image.load("saturn_image.jpg")

Be careful about using copyrighted images. If you publish a game with images that you don't have the rights to, that's illegal. If you are creating your own work that you aren't sharing, then it is ok. If you are doing a class assignment, make sure that you check with the instructor for his or her rules around it.

For class assignments, I suggest that you add a comment to the program just before loading the image. List where the image came from as was done in the example above. (Don't list Google as the image source, that's like listing the “library” as your reference source. Find the website the image came from.)

That code may load the image, but we have no way to reference that image and display it! We need a variable set equal to what the load() command returns. In the next version of our load command, we create a new variable named background_image. See below for version two:

background_image = pygame.image.load("saturn_image.jpg")

Finally, the image needs to be converted to a format Pygame can more easily work with. To do that, we append .convert() to the command to call the convert function. The function .convert() is a method in the Image class.

**If you've altered your image prior to loading, don't use .convert()

All images should be loaded using code similar to the line below. Just change the variable name and file name as needed.

background_image = pygame.image.load("saturn_image.jpg").convert()

Loading the image should be done before the main program loop. While it would be possible to load it in the main program loop, this would cause the program to fetch the image from the disk twenty or so times per second. This is completely unnecessary. It is only necessary to do it once at program start-up.

To display the image use the blit command. This “blits” the image bits to the screen.

The blit command is a method in the screen variable, so we need to start our command by screen.blit. Next, we need to pass the image to blit, and where to blit it. This command, .blit( ), should be done inside the loop so the image gets drawn each frame. See below:

screen.blit(background_image, [0, 0])

This code blit's the image held in background_image to the screen starting

at (0, 0).

7.4 Moving an Image

Now we want to load an image and move it around the screen. We will start off with a simple orange space ship. The image for a ship is HERE, or you can find a .gif or .png that you like with a white or black background. Don't use a .jpg.

To load the image we need the same type of command that we used with the background image. In this case, I'm assuming the file is saved as player.png.

player_image = pygame.image.load("player.png").convert()

Inside the main program loop, the mouse coordinates are retrieved, and passed to another blitfunction as the coordinates to draw the image:

# Get the current mouse position. This returns the position

# as a list of two numbers.

player_position = pygame.mouse.get_pos()

x = player_position[0]

y = player_position[1]


# Copy image to screen:

screen.blit(player_image, [x, y])

This demonstrates a problem. The image is a space ship with a solid black background. So when the image is drawn the program shows:

We only want the space ship, not a rectangular background! But all images we can load are rectangles, so how do we show only the part of the image we want? The way to get around this is to tell the program to make one color “transparent” and not display. This can be done immediately after loading. The following makes the color black (assuming BLACK is already defined as a variable) transparent:

player_image.set_colorkey(BLACK)

This will work for most files ending in .gif and .png. This does not work well for most .jpg files. The jpeg image format is great for holding photographs, but it does subtly change the image as part of the algorithm that makes the image smaller. Images in .gif and .png are also compressed, but the algorithms used in those formats do not change the image. The format .bmp isn't compressed at all, and results in huge files. Because the .jpg format changes the format, this means that not all of the background color will be the exactly the same. In the image below the space ship has been saved as a jpeg with a white background. The white around the ship is not exactly (255, 255, 255), but just really close.

If you are picking out an image that will be transparent, choose a .gif or .png. These are the best formats for graphic art type of images. Photos should be .jpg. Keep in mind it is not possible to change a .jpg to another format just by renaming the file extension to .png. It is still a .jpg even if you call it something different. It requires conversion in a graphics program to change it to a different format. But once in a .jpg format, it has been altered and converting it to a .png won't fix those alterations. A great places to find free images to use in your program: OpenGameArt.org

7.5 Sounds

In this section we'll play a laser sound when the mouse button is clicked. Sound files can also be found at OpenGameArt. You can download and save the sound here:

Laser Sound

Like images, sounds must be loaded before they are used. This should be done once sometime before the main program loop. The following command loads a sound file and creates a variable named click_sound to reference it:

click_sound = pygame.mixer.Sound("laser5.ogg")

We can play the sound by using the following command:

click_sound.play()

But where do we put this command? If we put it in the main program loop it will play it twenty times or so per second. Really annoying. We need a “trigger.” Some action occurs, then we play the sound. For example this sound can be played when the user hits the mouse button with the following code:

for event in pygame.event.get():

if event.type == pygame.QUIT:

done = True

elif event.type == pygame.MOUSEBUTTONDOWN:

click_sound.play()

Uncompressed sound files usually end in .wav. These files are larger than other formats because no algorithm has been run on them to make them smaller. There is also the ever popular .mp3 format, although that format has patents that can make it undesirable for certain applications. Another format that is free to use is the OGG Vorbis format that ends in .ogg.

Pygame does not play all .wav files that can be found on the Internet. If you have a file that isn't working, you can try using the program Audacity to convert it to an ogg-vorbis type of sound file that ends in .ogg. This file format is small and reliable for use with pygame.

If you want background music to play in your program, then check out this code:

How to play background music

Please note that you can't redistribute copyrighted music with your program. Even if you make a video of your program with copyrighted music in the background YouTube and similar video sights will flag you for copyright violation.