Lesson 9: Pygame
Lesson 9: Pygame
pyGame
Prepared by: Maria Kristela V. Fajardo, DIT
Exercise: Whack-a-mole
• Goal: Let's create a "whack-a-mole" game where moles pop
up on screen periodically.
– The user can click a mole to "whack" it. This leads to:
• A sound is played.
• The player gets +1 point.
• A new mole appears elsewhere on the screen.
2
What is pyGame?
3
pyGame at a glance
• pyGame consists of many modules of code to help you:
cdrom cursors display draw event
font image joystick key mouse
movie sndarray surfarray time transform
4
Game fundamentals
• sprites: Onscreen characters or other moving objects.
5
A basic skeleton
pygame_template.py
1 from pygame import *
2 from pygame.sprite import *
3
4 pygame.init() # starts up pyGame
5 screen = display.set_mode((width, height))
6 display.set_caption("window title")
7
8 create / set up sprites.
9
10 # the overall event loop
11 while True:
12 e = event.wait() # pause until event occurs
13 if e.type == QUIT:
14 pygame.quit() # shuts down pyGame
15 break
16
17 update sprites, etc.
18 screen.fill((255, 255, 255)) # white background
19 display.update() # redraw screen
6
Initializing pyGame
• To start off our game, we must pop up a graphical window.
• Calling display.set_mode creates a window.
– The call returns an object of type Surface, which we will call
screen. We can call methods on the screen later.
– Calling display.set_caption sets the window's title.
7
Surfaces
screen = display.set_mode((width, height)) # a surface
9
A rectangular sprite
from pygame import *
from pygame.sprite import *
class name(Sprite):
def __init__(self): # constructor
Sprite.__init__(self)
self.image = Surface(width, height)
self.rect = Rect(leftX, topY, width, height)
10
Rect methods
clip(rect) * crops this rect's size to bounds of given rect
collidepoint(p) True if this Rect contains the point
colliderect(rect) True if this Rect touches the rect
collidelist(list) True if this Rect touches any rect in the list
collidelistall(list) True if this Rect touches all rects in the list
contains(rect) True if this Rect completely contains the rect
copy() returns a copy of this rectangle
inflate(dx, dy) * grows size of rectangle by given offsets
move(dx, dy) * shifts position of rectangle by given offsets
union(rect) * smallest rectangle that contains this and rect
* Many methods, rather than mutating, return a new rect.
– To mutate, use _ip (in place) version, e.g. move_ip
11
A Sprite using an image
from pygame import *
from pygame.sprite import *
class name(Sprite):
def __init__(self): # constructor
Sprite.__init__(self)
self.image = image.load("filename").convert()
self.rect = self.image.get_rect().move(x, y)
12
Setting up sprites
• When creating a game, we think about the sprites.
– What sprites are there on the screen?
– What data/behavior should each one keep track of?
– Are any sprites similar? (If so, maybe they share a class.)
13
Sprite groups
name = Group(sprite1, sprite2, ...)
– To draw sprites on screen, put them into a Group
– Useful methods of each Group object:
draw(surface) - draws all sprites in group on a Surface
update() - calls every sprite's update method
14
Events
• event-driven programming: When the overall program is
a series of responses to user actions, or "events."
15
The event loop
– In an event loop, you wait for something to happen, and then
depending on the kind of event, you process it:
while True:
e = event.wait() # wait for an event
if e.type == QUIT:
pygame.quit() # exit the game
break
elif e.type == type:
code to handle some other type of events;
elif ...
16
Mouse events
• Mouse actions lead to events with specific types:
– press button down: MOUSEBUTTONDOWN
– release button: MOUSEBUTTONUP
– move the cursor: MOUSEMOTION
e = event.wait()
if e.type == MOUSEMOTION:
pt = mouse.get_pos()
x, y = pt
...
17
Collision detection
• collision detection: Examining pairs of sprites to see if
they are touching each other.
– e.g. seeing whether sprites' bounding rectangles intersect
– usually done after events occur,
or at regular timed intervals
– can be complicated and error-prone
• optimizations: pruning (only comparing some sprites, not all), ...
18
Collisions btwn. rectangles
• Recall: Each Sprite contains a Rect collision rectangle
stored as a field named rect
• Rect objects have useful methods for detecting collisions
between the rectangle and another sprite:
collidepoint(p) returns True if this Rect contains the point
colliderect(rect) returns True if this Rect touches the rect
if sprite1.rect.colliderect(sprite2.rect):
# they collide!
...
19
Collisions between groups
global pyGame functions to help with collisions:
spritecollideany(sprite, group)
– Returns True if sprite has collided with any sprite in the group
20
Drawing text: Font
• Text is drawn using a Font object:
name = Font(filename, size)
– Pass None for the file name to use a default font.
Example:
my_font = Font(None, 16)
text = my_font.render("Hello", True, (0, 0, 0))
21
Displaying text
• A Sprite can be text by setting that text's Surface
to be its .image property.
Example:
class Banner(Sprite):
def __init__(self):
my_font = Font(None, 24)
self.image = my_font.render("Hello", True, \
(0, 0, 0))
self.rect = self.image.get_rect().move(50,70)
22
Exercise: Pong
• Let's create a Pong game with a bouncing ball and paddles.
– 800x480 screen, 10px white border around all edges
– 15x15 square ball bounces off of any surface it touches
– two 20x150 paddles move when holding Up/Down arrows
– game displays score on top/center of screen in a 72px font
23
Animation
• Many action games, rather than waiting for key/mouse
input, have a constant animation timer.
– The timer generates events at regular intervals.
– On each event, we can move/update all sprites, look for
collisions, and redraw the screen.
24
Timer events
time.set_timer(USEREVENT, delayMS)
while True:
e = event.wait()
if e.type == USEREVENT:
# the timer has ticked
...
25
Key presses
• key presses lead to KEYDOWN and KEYUP events
• key.get_pressed() returns an array of keys held down
– the array indexes are constants like K_UP or K_F1
– values in the array are booleans (True means pressed)
– Constants for keys: K_LEFT, K_RIGHT, K_UP, K_DOWN,
K_a - K_z, K_0 - K_9, K_F1 - K_F12, K_SPACE,
K_ESCAPE, K_LSHIFT, K_RSHIFT, K_LALT, K_RALT,
K_LCTRL, K_RCTRL, ...
keys_down = key.get_pressed()
if keys_down[K_LEFT]:
# left arrow is being held down
...
26
Updating sprites
class name(Sprite):
def __init__(self):
...
27
Sounds
• Loading and playing a sound file:
from pygame.mixer import *
mixer.init() # initialize sound system
mixer.stop() # silence all sounds
Sound("filename").play() # play a sound
28
The sky's the limit!
• pygame.org has lots of docs and examples
• can download tons of existing games
– run them
– look at their code for ideas
• if you can imagine it,
you can create it!
29