learn Python. Create Games

User Tools

Site Tools


Step 018 - Mask and pixel perfect collision detection


the yellow impact circles show the collide_circle In this variation of the previous game, you can toggle with the <key>c</key> key between the three different methods for collision detection:

  1. collide_rect - the default method, and the fastest of all. sprites need a self.rect attribute
  2. collide_circle - slower but better looking. sprites need a self.radius attribute
  3. collide_mask - the slowest but most precise method. sprites need a self.mask attribute, taken from the sprites image.

Fly the smaller penguin around (with <key>w</key> <key>a</key> <key>s</key> <key>d</key> <key>q</key> <key>e</key>, shoot at the big penguin with <key>space</key> and check the pattern of the yellow impact “wounds” depending of the different collide methods.

A bitmask is like an image with only two colours: collision-relevant and non-relevant. Like an black / white photograph. You can create your own bitmask but pygame has a command to create a bitmaks from an image:

pygame.mask.from_surface(Surface, threshold = 127) -> Mask

Note that if you rotate a sprite and rotate the sprite's image, you must create a new mask from the rotated image.

collision dedection

       #.. inside mainloop
                elif event.key == pygame.K_c:
                    if collision == "rect":
                        collision = "circle"
                    elif collision == "circle":
                        collision = "mask"
                    elif collision == "mask":
                        collision = "rect"
                    screentext2.newmsg("collsion detection: %s" % collision)
        # ...
        # ------ collision detection
        for bird in birdgroup:
            if collision == "rect":
                crashgroup = pygame.sprite.spritecollide(bird, bulletgroup, False, pygame.sprite.collide_rect)
            elif collision == "circle":
                crashgroup = pygame.sprite.spritecollide(bird, bulletgroup, False, pygame.sprite.collide_circle)
            elif collision == "mask":
                crashgroup = pygame.sprite.spritecollide(bird, bulletgroup, False, pygame.sprite.collide_mask)
            for ball in crashgroup:  # test for collision with bullet
               # ...

problem: sprites overshooting each other

There is a common problem if you test very small, very fast sprites for collisions with small objects: the fast sprite is “teleporting” or overshooting over the obstacle, not triggering a collision detection. Some quick solutions are:

  • use slower, bigger sprites and bigger obstacles
  • use a higher framerate
  • use a self.radius value of a sprite that is far bigger than the actual sprite. Use this self.radius together with pygame.sprite.collide_circle for collision detection
  • experts: calculate if 2 vectors, originating from self.pos with self.dx,self.dy cross each others.

what's new

class chart of part2step18. click to enlarge The code is nearly the same code as in the previous example. The Fragment class has a new sub-class, called Wound. It simply produces an yellow ball for some time, attached to the target (the giant penguin).

GiantBird is another subclass of the Bird class, producing an giant penguin (zoom x 4!) and moving around by random.

source code on github

To run this example you need:

file in folder download pygame Download the whole Archive with all files from Github:
from Battle of Wesnoth
bomb.ogg pygame/data
shoot.ogg pygame/data
beep.ogg pygame/data

View/Edit/Download the file directly in Github:

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

comment this page


/var/www/horst/ · Last modified: 2014/01/09 11:07 (external edit)