Intro
Pygame is a library for making arcade style sprite games
It features very easy blitting and colision detection
I have some sample code to help with understanding pygame here: https://code.edge.launchpad.net/~rick-rickspencer3/pygame-template/trunk
note that this is a bit old, and I need to reformat it and such
however, it will eventually be a quickly template, hopefully in time for lucid
if you want to grab that it might help you follow the class a bit, but it is not required
it comes with some basic game play that you can study and modify
essentially, it is kind of like asteroids
you control the black triangle in the middle, and there are two enemies
Of course you will want some docs
Pygame has good docs here:
Setting up a game
first thing you need to do is set up a game surface
initialize pygame libraries
pygame.font.init() pygame.mixer.init()
then create a screen
the screen will be the surface on which your sprites will be drawn, essentially where your game will occur
screen = pygame.display.set_mode((800, 480))
also, create a couple of variable you will need later
like a background image
background = pygame.image.load(path_to_background)
and a clock
clock = pygame.time.Clock()
pygame games use a good old fashioned input loop
essentially, you tell your app to keep looping
and whenever it goes through the loop do a few things
respond to user input
update data for any sprites on the screen
this includes seeing if any sprites have collided
tell the app to update itself
let's look at setting up a game loop
- while 1:
- clock.tick(15)
if ControllerTick() == 0:
- return
ViewTick() if CheckCollisions() == 0:
- return
- clock.tick(15)
you can see this code in the crashteroids file at line 169
so first, the loop just runs and runs until etiher ControllerTick or CheckCollisions returns 0
the first line in the loop basically says to have 15 frames per second
this is not like a sleep function where the argument says how long to sleep
make sure that you pick a number that is low enough that a lower powered computer can keep up, if you care about that kind of thing
The next line calls ControllerTick
This function checks for user input, which I will explain in a moment, and the updates all the game data
Then assuming that the game is not paused, it will go ahead and update the view and do collision detection
The reason that controllertick is always called is because this function controlls pausing and unpausing of the game
we'll look at each of these functions in more detail now
But first, questions?
using input
pygame basically queues up input events
you can then loop through them and respond to each event
at line 93, you can see how the loop is set up
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- return 0
- if event.type == pygame.QUIT:
pygame.QUIT is called when the window closes or such
of course you could also do something smart and save game state or such
but this code returns 0, which causes the main event loop to quit
now, let's say what I want to do is make the ship go forward when the user presses the j key
first I ask what kind of event it was
- if event.type == pygame.KEYDOWN:
and then if it was a key event, what key was pressed
- if event.key == pygame.K_l:
- #do something
you can see the whole tree of if, else statements starting at line 89
there are also events for the mouse and joysticks even
so it's easy to create games that aren't only using the keyboard if you want
so that's how to handle input
let's look at sprites, but first, any questions?
managing a sprite
A sprite is basically an image in an arcade game
pygame handles blitting for you, which is quite nice
I'll discuss blitting in a bit
If you wrote games long ago, you may remember rendering a sprite strip to an offscreen graphics world
and then selecting bits of that strip and copying them to the onscreen graphics world
pygame does not reqiure that at all
it is much more fun and easy
you just subclass the Sprite class
the key thing a sprite has is an Pygame.Image member, called image
I usually like to keep the original image around, as if you keep rotating the image and such, it will get more and more distorted over time
so I set the image object like this
- self.masterImage = pygame.image.load(path_to_image_file) self.image = self.masterImage
a sprite also has a "virtual" function, called update
update is supposed to be called to tell a sprite to update it's data for a tick
you set things like the sprite's x, y coordinates in this function, and such
all your sprites should use this because you can then add a sprite to a RenderUpdates sprite group
and then call update for that group, which will call update for each sprite
you create a sprite group like this: enemies = pygame.sprite.RenderUpdates()
and then you can add an sprite to that group enemies.add(create_enemy())
you can also empty a sprite group
enemies.empty()
useful when you are resetting a level or something
as we'll see later, sprite groups also help lots with collision detection
back to sprites though
so you have an image on a sprite
you also need to define an x and y for your sprite
I in my sprite subclass, I might set x and y randomly like this:
- self.x = random.randint(0,300) self.y = random.randint(0,140)
but then on each call to update(), just change the x and/or y if the sprite is moving
sprites also have a "kill()" member function
calling kill causes the sprite to be removed from the playing surface
questions before we talk about updating the display?
= updating the display so now you have your event loop running, your game surface set up, and some sprites created
now we need to actually draw the sprites
for sprites that are not in a sprite group, we need to blit them
fortunately this does not involve the crazy gworld hackery of days of hold
pygame gives us a blit method
blitting is essentially the act of repainting parts of the screen that have changed
without blitting, the whole screen repaints and appears to flash
so to blit the blackgroud, we'll use the screen to blit
remember when we created teh screen object? now it's time to use it
screen.blit(background, [0,0])
blitting the background like this basically repaints the whole background image over everything
if you are tuning for a very slow platform, or a game with lots and lots of sprites, you can't do it this way or you get flashing
in those cases you need to track the parts of the background exposed by moving sprites
this is a bit of work, but probably will not be necessary for you to do
to blit an individual sprite, you have to tell the screen the image to use and the rect, or xy coords and dimensions, for hte sprite to blit
So if we have a sprite object called "g", we blit it like this:
screen.blit(g.image, g.rect)
sprites in a sprite group are a bit easier to blit
you can tell the sprite group to blit them all:
- enemies.draw(screen)
this blits all the enemies for you
question before we discuss collision detection?
collision detection
so let's say when an enemy rams our guy, we want both to be killed
but how to tell when an ememy hits?
detecting overlapping sprites is called "collision detection" and is handled quite well by PyGame
this saves you tons of work
you can detect if two sprites have collided using pygame.sprite.spritecollide (), collideany, or groupcollide
so let's see if our guy, called g, has collided with an enemy
- e = pygame.sprite.spritecollideany(g, enemies)
call this each tick
if the guy has not collided with any enemies, e will be None
but when e is not None, that means boom
let's say your guys shoots bullets
those bullets will most likely be managed in a sprite group
so we should also see if any enemies were killed by bullets
hits_dict = pygame.sprite.groupcollide(bullets, enemies, False, False)
here you get back a dictionary
the keys are sprites from the first sprite group
and the values are keys from the second sprite group
so then we can just go through and kill each bullet and enemy for the collision:
- for b in hits_dict:
- for e in hits_dict[b]:
- e.kill() b.kill()
- for e in hits_dict[b]:
ok, next and last section is on playing sounds
any questions first?
playing sounds
we use the Pygame.mixer module to manage sounds
we need to initialize it before we use it:
pygame.mixer.init()
now I'll load an explosion sound to play when my guy explodes:
self.explosionSound = pygame.mixer.Sound(path_to_sound_file)
let's assume this sound is a bit loud, we can adjust the volume as we like:
- self.explosionSound.set_volume(.2)
then we can play the sound:
- self.explosionSound.play()
we can stop it too if it's going too long:
- self.explosionSound.stop()
the mixer module is quite rich
there are channels, fades, and all kinds of stuff
ok, any last questions?