In this chapter we move onto something a little more interesting – using functions from the Pygame library to draw images to the screen and play sounds, among other things.
In the following program, the player’s tank can be moved around using the arrow keys, and a message is printed if the player collides with the alien. To quit, click on the close window icon.
The code for the program can be found in the file Pygame Example.py and below is an explanation of each section:
# 1 import basic pygame modules
import pygame
from pygame.locals import *
The code starts by importing the Pygame library into the program, this library provides the functionality to write 2D video games. For example, drawing images onto the screen or playing sounds. The bare Python language itself is unable to do much beyond basic text programs, so we extend its functionality with Pygame. This isn’t a flaw with Python, it’s a similar situation in other programming languages – to do anything useful you need to extend their functionality with libraries.
# 2 Initialize pygame
pygame.init()
The Pygame library needs to be initialized before it can be used and this line does exactly that.
# 3 Constants
PLAYERSPEED = 5
Constants are containers for data, similar to variables, but the values they hold are fixed and don’t change. It’s customary to use all capital letters for their names. The number 5 means move the player 5 pixels when a key is pressed.
# 4 Set the display mode
surScreen = pygame.display.set_mode ([640,480],0)
This function creates a display surface on which the graphics are drawn. The 640, 480 arguments indicate the width and height of the window in pixels, and the 0 specifies it is software driven (using the CPU instead of a graphics card.)
# 5 load graphics
surBackground = pygame.image.load ('background2.gif')
surPlayer = pygame.image.load('player1.gif')
surAlien = pygame.image.load('alien1.gif')
The graphics files are loaded into the program and each one returns a surface object which are given names to refer to them.
# 6 load music and play it
pygame.mixer.music.load('house_lo.wav')
pygame.mixer.music.play(-1)
The music is loaded and then started playing. The argument in the play() function controls how many times the music is repeated, -1 plays it indefinitely.
# 7 create rectangles for collision detection
recPlayer = Rect(250,400, surPlayer.get_width(), surPlayer.get_height())
recAlien = Rect(450,200, surAlien.get_width(), surAlien.get_height())
Two rectangle objects are created for the player and the alien to enable collision detection when they overlap (rectangle objects hold x and y coordinates as well as width and height.) The numbers are the starting positions (in pixels) and the widths and heights are retrieved from the respective surface objects.
# 8 misc variables
booCollision = False
booKeepPlaying = True
The collision flag is used to indicate whether or not the player and alien have collided. It’s set to true if there’s a collision and later on in the code a message is displayed to indicate this. The second flag controls the repeating of the main loop, and is set to false when the user clicks the close window button (ending the game.)
# 9 main game loop
while booKeepPlaying:
This is the main game loop and it continues repeating until booKeepPlaying becomes False when the user clicks on the close window button.
# 10 get keyboard input
for event in pygame.event.get():
if event.type == QUIT:
booKeepPlaying = False
Here we get a list of any events that have occurred, an event being for instance a key press or a mouse button click. If the user clicks on the window close icon it will generate a QUIT event type and booKeepPlaying is made false, ending the main loop and the game.
# 11 respond to key presses
keyInput = pygame.key.get_pressed()
if keyInput[K_RIGHT]:
recPlayer.x += PLAYERSPEED
if keyInput[K_LEFT] :
recPlayer.x -= PLAYERSPEED
if keyInput[K_UP]:
recPlayer.y -= PLAYERSPEED
if keyInput[K_DOWN]:
recPlayer.y += PLAYERSPEED
get_pressed returns a sequence of values indicating which keys have been pressed, and this is assigned to the variable keyInput. Then there are four tests to see whether the player has pressed any keys. K_RIGHT K_LEFT K_UP or K_DOWN are numerical indexes to the keyInput sequence, and each expression has a result of True or False. If the right arrow key is pressed then the player’s horizontal or x coordinate is increased by the value of PLAYERSPEED. This x coordinate is a field of data in the player’s rectangle object. If the left arrow key is pressed then PLAYERSPEED is subtracted from the x coordinate moving the player left. Similarly pressing the up arrow reduces the y or vertical coordinate moving the player up the screen. The opposite applies when the down key is pressed.
# 12 draw graphics
surScreen.blit(surBackground, (0,0))
surScreen.blit(surAlien, (recAlien.x,recAlien.y))
surScreen.blit(surPlayer, (recPlayer.x,recPlayer.y))
if booCollision == True:
strCollision = "COLLISION!"
imgCollision = pygame.font.Font(None,40). render(strCollision, 0, Color('white'))
surScreen.blit(imgCollision, (250,50))
pygame.display.flip()
This section uses 4 blits (image transfers) to draw graphics on the screen. First the background is drawn which has the effect of erasing all the previous graphics on the screen and replacing it with the fresh background. If this wasn’t done then the player’s image would leave a trail behind it as it was moved around. Next the player and alien images are drawn to the screen. The final blit creates an image from the string ‘COLLISION!’ and then draws it on screen. The display.flip() function is necessary to update the display.
# 13 detect player collision with alien
if recPlayer.colliderect(recAlien)==True:
booCollision = True
else:
booCollision = False
The colliderect method of the recPlayer object is used to test if it collides with or overlaps the alien’s rectangle object recAlien. If it does then booCollision is set to True and on the next iteration of the main loop ‘COLLISION!’ is written on the screen. If the rectangles do not overlap, then booCollision is set to False and the string is not displayed.
# 14 cap the framerate
clock = pygame.time.Clock()
clock.tick(40)
Here we get a clock object and use one of its methods to introduce a pause or time delay into the program. This will make the main loop repeat itself no more than 40 times (or frames) per second, which is an adequate rate for this game. Without this delay the loop would run at the maximum speed the CPU is capable of, and slow down the user’s system.
Comic Relief
What do you call 8 hobbits?
A hobbyte