ThePythonGameBook

learn Python. Create Games

User Tools

Site Tools


en:pygame:step014

Step 014 - Pygame sprites

code discussion

many many sprites If you analyze the previous catch-the-thief game you will notice that most of the code in the main loop takes care of cleaning, calculating and blitting the pygame surfaces (the sprites). Pygame provides a very powerful pygame.sprite class for more elegant and object-oriented sprite programming.

The advantages of using a sprite class are:

  • you code the sprite class once and can have multiple instances (sprites flying around) with little extra coding
  • all relevant methods (bounce from screen edge) and property's (colour, size, rotation) are coded inside the sprite class and not in the main loop
  • each sprite has it's own values and functions (with a prefix, mostly self) but you can also use class-width values and functions for all sprites of the same class (like all thieves)
  • you can organize the sprite instances into pygame.sprite.Groups for mass processing
  • pygame provides easy-to-use collision detection between sprites

what is a class ?

Please refer to the python documentation or other tutorials for a better introduction into object-oriented programming. For quick and dirty coding, it is enough if you compare using a sprite class with the process of making cookies:

With just one Cookie_cutter you can construct many cookies. Think of the cookie cutter as the class and of the cookies as the (constructed) instances of this class. The class (the cookie cutter) defines the property (the look and feel) of all the instances (the cookies) but the class is no instance itself (you can not eat the cookie cutter).

code example of a sprite class

dough + cookie cutter = cookies
dough a cookie cutter many cookies
some coding class many class instances (sprites)
class Snake(pygame.sprite.Sprite):
    """the pygame Snake"""
    image = pygame.image.load("Snake.gif")
    image = image.convert_alpha()
    def __init__(self, startpos):
       pygame.sprite.Sprite.__init__(self,
                              self.groups) 
       self.pos = startpos
       self.image = Snake.image 
       self.rect = self.image.get_rect()
    def update(self):
       self.rect.center = self.pos
many sprites

discussion of sprite classes

In the code example above (below the cookies) you can how a sprite class looks like. It is custom to write the class name (after the keyword class) with a beginning capital Letter, in this case Snake instead of snake. Also note that this class derives from (is a child of) pygame's Sprite class.

class Snake(pygame.sprite.Sprite):

Directly after the class code lines comes the docstring (where you describe what the class should do). The next two lines

    image = pygame.image.load("Snake.gif")
    image = image.convert_alpha()

describe class-wide property and functions, shared by all instances of this class. In this examples, it makes sense to load the image file from the harddisk once and not every time a new Snake sprite is born.

class prefix self

Now comes the part describing each class instance (each individual Snake). To refer to itself as an class instance, the prefix self is used. You could use another prefix but most python coders write self. Each function need at least the argument self, even if no other parameter is passed to the function. The first function that every pygame sprite class need is the function to create a new instance of the class (a new Snake should be born). Because this function is so special pygame needs two underscores before and after it's name:

def __init__(self):

A part from the usual self, you can give the new born Snake as many arguments as you need, like initial position, behaviour, color etc. In the next example, only a startpos is given, defaulting to (50,50) if the sprite is created without a startpos.

The sprite will not work until you tell pygame to do all the stuff that it needs doing to create a new sprite. This is done by calling the __init__ function of the class (Snake) parent's class (pygame.sprite.Sprite), also a good way to handle pygame's sprite groups.

storing class parameters

If you want to store any parameters for the sprite itself (so that other functions like an update or kill function can access them, you need to save the parameter into a class instance variable with a proper prefix (self).

It is best you always think of these two lines as one organic block, like flour and water:

def __init__(self, startpos=(50,50)):
       pygame.sprite.Sprite.__init__(self,self.groups) # never forget this line !
       self.pos = startpos                        # store startpos into a class instance variable with the prefix self.

call the property of the class

Now you are free to code all the property's of the class instance. Remember to write the prefix self to indicate that a property (like the position) is valid or this individual snake (class instance) only. Here, the starpos argument is stored into the variable self.pos:

self.pos = startpos

To access class-wide variables, simply call the name of the class (note the capital letter at the beginning):

self.image = Snake.image

useful stuff for each class

  • self.image …how the sprite look. It's a pygame surface, loaded or created, and you can use the pygame.draw commands on it.
  • self.rect …very useful, get it with the command self.rect = self.image.get_rect() after you are done with creating self.image
  • self.radius … useful for circular collision detection
  • self.rect.center … if you have self.rect, use this to control the postion of a sprite on the screen.
  • update(self, time): … a function (best with the passed seconds since last frame as argument) where you can calculate what the sprite should do, like moving, bouncing of walls etc
  • kill(self) … very useful to destroy a sprite. the call inside the class is self.kill(), in the mainloop you would call snake222.kill()

a complete sprite class

This is the complete code for the Birdcatcher class in the example game (see source code. This class consist of a red circle centred around the mouse pointer. As you can see the code to create the BirdCatcher image is shared for all instances of the class. Each individual BirdCatcher sprite has it's own self.image.

class BirdCatcher(pygame.sprite.Sprite):
    # class variables shared by all instances of this class
    image = pygame.Surface((100,100)) # created on the fly
    image.set_colorkey((0,0,0)) # black transparent
    pygame.draw.circle(self.image, (255,0,0), (50,50), 50, 2) # red circle
    image = self.image.convert_alpha()
    # code for each individual class instance
    def __init__(self):
        pygame.sprite.Sprite.__init__(self, self.groups) # THE most important line !
        self.image = BirdCatcher.image # make class-variable an instance variable
        self.rect = self.image.get_rect()
        self.radius = 50 # for collide check
    def update(self, seconds):
        # no need for seconds but the other sprites need it
        self.rect.center = pygame.mouse.get_pos()
 

before the main loop

Before the main loop starts, you define some pygame.sprite.Groups to contain all the sprites: If you have a Sprite Snake and the two groups allgroup and snakegroup you can assign that all Snake sprites should be members of both groups:

allgroup = pygame.sprite.Group()
snakegroup = pygame.sprite.Group()
# each Snake sprite is automatically member of both groups:
Snake.groups = allgroup, snakegroup
# create a single Snake named "mypython"
mypython = Snake() 

what to do in the mainloop

You must make sure that your sprites belong to a sprite group (like allsprites). In the mainloop, you simply call those commands each frame:

allsprites.clear(screen, background)
allsprites.update(seconds)
allsprites.draw(screen)
pygame.display.flip()

documentation

source code on github

To run this example you need:

file in folder download
014_sprites.py pygame Download the whole Archive with all files from Github:
https://github.com/horstjens/ThePythonGameBook/archives/master
babytux.png
babytux.png
pygame/data
babytux_neg.png
babytux_neg.png
pygame/data

View/Edit/Download the file directly in Github: https://github.com/horstjens/ThePythonGameBook/blob/master/pygame/014_sprites.py

click reload in your browser if you see no code here:

comment this page

~~DISQUS~~

/var/www/horst/thepythongamebook.com/data/pages/en/pygame/step014.txt · Last modified: 2014/01/09 11:07 (external edit)