Table of Contents
Step 018 - Mask and pixel perfect collision detection
- collide_rect - the default method, and the fastest of all. sprites need a self.rect attribute
- collide_circle - slower but better looking. sprites need a self.radius attribute
- 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 W A S D Q E, shoot at the big penguin with Space 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.
#.. 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.
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:
|018_perfect_collision_detection.py|| || Download the whole Archive with all files from Github:
| babytux.png ||
| crossmonster.png ||
| xmonster.png ||
| claws.ogg |
from Battle of Wesnoth
View/Edit/Download the file directly in Github: https://github.com/horstjens/ThePythonGameBook/blob/master/pygame/018_perfect_collision_detection.py
click reload in your browser if you see no code here: