Lab 5: PyGame Tidbits
This lab is a chance to do some free-form experimentation with different abilities in PyGame.
Below, I've listed lots of different features and how to use them, feel free to try applying them to some of the pygame examples we've worked on in the earlier labs.
Be sure to read the pygame documentation for the (many) additional features and options.
Once we've taken a rectangle around an image we can use a number of the rectangle's attributes to specify how/where it should be placed on the display, all based on the x,y pixel coordinates.
# load an image and get a box/rectangle around it myImage = pygame.image.load('somefile.gif') myBox = myImage.get_rect() # try various ways to position the image around the center of the screen x,y = screenWidth/2, screenHeight/2 myBox.left = x myBox.right = x myBox.topleft = (x,y) myBox.topright = (x,y) myBox.bottomleft = (x,y) myBox.bottomright = (x,y) myBox.center = (x,y) myBox.midtop = (x,y) myBox.midleft = (x,y) myBox.midright = (x,y) myBox.midbotton = (x,y) # display the size of the box print myBox.w print myBox.h print myBox.size print myBox.width print myBox.heightWe can also use a variety of rectangle routines to change the size of the box around an image, or to join multiple boxes together into one big box:
# get a new box that is bigger/smaller than the ship by x,y newBox = shipBox.inflate(x, y) # get a new box that is just the part of the star inside the ship # (assuming they overlap) newBox = starBox.clip(shipBox) # get a new box that encloses both the star and the ship # (assuming they overlap) newBox = starBox.union(shipBox)
When we first set up our displays, we initialized pygame and used set_mode to set up the size of the window, e.g.
import pygame pygame.init() size = 640, 480 display = pygame.display.set_mode(size)We can also put a caption on the window, e.g. adding
Pygame allows us to take an image and create variants (transformations) of it, specifically by rotating it, flipping it, or changing its size:
# load the original version of the image originalImage = pygame.image.load("somefile.gif") # create the version we'll be rotating and displaying realVersion = pygame.transform.rotate(originalImage, 0) realBox = realVersion.get_rect() # rotate it 90 degrees and display it realVersion = pygame.transform.rotate(originalImage, 90) display.blit(realVersion, realBox) # now flip it horizontally realVersion = pygame.transform.flip(originalImage, True, False) display.blit(realVersion, realBox) # now flip it vertically realVersion = pygame.transform.flip(originalImage, False, True) display.blit(realVersion, realBox) # now flip it horizontally AND vertically realVersion = pygame.transform.flip(originalImage, True, True) display.blit(realVersion, realBox) # now resize it, giving a new width and height (pixels) realVersion = pygame.transform.scale(originalImage, (100, 120)) display.blit(realVersion, realBox)
To draw text, you first create a font variable, then use that to "render" the text and place the text on the screen:
The PyGame draw module provides many routines for drawing lines, rectangles, circles, polygons, arcs, etc.
In general, these involve specifying the screen to draw on, the colour to use, the key coordinates or sizes, and the thickness of the lines used in drawing the shape. E.g.:
# draw a black line of width 3, from position 10,100 to position 50,200 pygame.draw.line(display, black, (10,100), (50,200), 3) # draw a polygon with line width 3 and "corners" at the list of (x,y) points # (if you use a width 0 it fills in the polygon) myPoints = [(10, 12), (20,30), (25,12), (17,8), (6,10)] pygame.draw.polygon(display, black, myPoints, 3) # draw a red circle with line width 3 and radius 10 centered around point (50,70) # (if you use a width 0 it fills in the circle) pygame.draw.circle(display, red, (50,70), 10, 3)
The PyGame mixer module provides many routines for playing sound effects and music.
To play sounds, one must first load the sound file using the
pygame.mixer.Sound routine, e.g.
explosion = pygame.mixer.Sound("explosion.wav")
Anytime after that, you can play the sound effect using
the play routine, e.g.
explosion.play()
You can set the volume anywhere between 0.0 (off) and 1.0 (max),
e.g.
explosion.set_volume(0.7)
You can also stop the sound, e.g. explosion.stop()
To play background music, one uses a different routine to
load the file, pygame.mixer.music.load after which
you can issue the music.play command,
telling it how many times to repeat, e.g.:
pygame.mixer.music.load("muzac.wav")
pygame.mixer.music.play(-1)
(Telling it to repeat -1 times will cause it to repeat endlessly.)
You can control the volume, again between 0 and 1, e.g.
pygame.mixer.music.set_volume(0.5)
You can also rewind, pause, unpause, or stop the currently playing music, e.g.
pygame.mixer.music.rewind()
pygame.mixer.music.pause()
pygame.mixer.music.unpause()
pygame.mixer.music.stop()
As with sound and music, PyGame supports playing animations, which must be loaded first and then can be played, stopped, rewound, etc. E.g.
myMovie = pygame.movie.Movie('someMovie.mpeg') .... myMovie.play(3) # the number tells it how often to repeat myMovie.rewind() myMovie.set_volume(0.6) myMovie.stop()
To get random events or characteristics in the game we typically use built-in routines to generate random numbers, then have different things happen depending on which number came up.
At the start of the program, we need to import and
initialize the random number
generator by including the commands
import random
random.seed()
Anytime after that, and as often as you like, you can generate new random integers by specifying what range they should come from, e.g.
# initialize the random number generator import random random.seed() # generate a random number between 10 and 100 myNum = random.randint(10, 100) # generate a random number between 5 and 200 myNum = random.randint(5, 200)
We often need timers in games, to establish delays between events (e.g. generate a new enemy every 30 seconds, or 10 seconds after the player enters a room, etc).
There are a handful of routines for obtaining the current time in game, pausing the program for set amounts of time, and setting timed events using pygame:
To avoid conflicts with the build in event types, we pick an 'id' value that is between pygame.USEREVENT and pygame.NUMEVENTS, e.g.
# pick id numbers for two kinds of timed events wanderingMonsterID = pygame.USEREVENT patrollingGuardID = pygame.USEREVENT + 1 # set up timers to go off every 120 seconds for the monsters # and every 200 seconds for the guards pygame.time.set_timer(wanderingMonsterID, 120000) pygame.time.set_timer(patrollingGuardID, 200000) # inside our event processing loop, add code that should # run whenever the timers go off for event in pygame.event.get(): # see if it was one of our timer events if event.type == wanderingMonsterID: print "ah, here we should do something about wandering monsters" if event.type == patrollingGuardID: print "and here we should do something about patrolling guards"
Sometimes we may want to get or change the position or visibility of the mouse on the screen.
Pygame provides a few routines for handling this, such as:
x,y = pygame.mouse.get_pos() # looks up the current position of the cursor pygame.mouse.set_pos(x,y) # moves the cursor to the specified position pygame.mouse.set_visible(False) # hides the cursor pygame.mouse.set_visible(True) # shows the cursor
In our first few labs we looked at using a for loop to process different kinds of events. The example below looks at a wider range of possible events.
for event in pygame.event.get(): # check if the user has closed the window if event.type == pygame.QUIT: # do something appropriate # check if the user has pressed a key if event.type == pygame.KEYDOWN: # look at event.key to see which key they pressed # look at event.mod to see if they are also holding down alt, shift, etc # check if the user has released a key if event.type == pygame.KEYUP: # look at event.key to see which key they pressed # look at event.mod to see if they are also holding down alt, shift, etc # check if the user has pressed a mouse button if event.type == pygame.MOUSEBUTTONDOWN: # look at event.button to see which button they pressed # look at event.pos to see the x,y position of the mouse # check if the user has released a mouse button if event.type == pygame.MOUSEBUTTONUP: # look at event.button to see which button they released # look at event.pos to see the x,y position of the mouse # check if the user has moved the mouse if event.type == pygame.MOUSEMOTION: # look at event.pos to see the new x,y position of the mouseHere is a list of just some of the names for the different keys:
K_0, K_1, ..., K_9, K_F1, K_F2, ..., K_F15, K_a, K_b, K_c, ..., K_z, K_A, K_B, ..., K_Z, K_BACKSPACE, K_TAB, K_CLEAR, K_RETURN, K_PAUSE, K_ESCAPE, K_SPACE, K_EXCLAIM, K_QUOTEDBL, K_HASH, K_DOLLAR, K_AMPERSAND, K_QUOTE, K_LEFTPAREN, K_RIGHTPAREN, K_ASTERISK, K_PLUS, K_COMMA, K_MINUS, K_PERIOD, K_SLASH, K_COLON, K_SEMICOLON, K_LESS, K_AT K_EQUALS, K_GREATER, K_QUESTION, K_LEFTBRACKET, K_RIGHTBRACKET, K_BACKSLASH, K_CARET, K_BACKQUOTE, K_DELETE, K_UP, K_DOWN, K_LEFT, K_RIGHT, K_INSERT, K_HOME, K_PAGEUP, K_PAGEDOWN, K_END, K_CAPSLOCK, K_NUMLOCK, K_SCROLLOCK, K_RSHIFT, K_LSHIFT, K_RCTRL, K_LCTRL, K_RALT, K_LALT, K_MODE, K_HELP, K_BREAK, K_MENU, K_PRINT, |
If we have two rectangles, we can use the colliderect routine
to see if they overlap, e.g.
if (starBox.colliderect(shipBox)):
There are a number of additional routines available, e.g.
# check if starBox overlaps with anything in a list of boxes if (starBox.collidelist(listOfBoxes)): # do something appropriate # check if starBox overlaps an x,y point: if (starBox.collidepoint(x, y)): # do something appropriate # check if one rectangle is completely inside another: if (shipBox.contains(starBox)): # do something appropriate