PyGameClassNotes

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:

http://www.pygame.org/docs/

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

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

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()

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?

UbuntuOpportunisticDeveloperWeek/PyGameClassNotes (last edited 2010-03-03 02:37:19 by rick-rickspencer3)