pythonimagepygamepixel-perfect

How to use pixel perfect collision with two images pygame


Note: I do not want to use pygame sprites.

I am making a simple game and I need a way to detect if two images overlap using pixel-perfect collision in pygame. All the answers I have found so far require that I use pygame sprites, which I prefer not to use because I have less control over the objects.

(These images have transparent backgrounds)


Solution

  • First of all, don't be afraid of Sprites.

    A Sprite is just a simple class with an image (a Surface that is stored in the image attribute) and the size and position of the image (a Rect stored in the rect attribute).

    So when you use a class like this:

    class Player:
        def __init__(self, image, pos):
            self.image = image
            self.pos = pos
    
        def draw(self, screen):
            screen.blit(self.image, self.pos)
    

    you could simple use the Sprite class instead, since not much would change:

    class Player(pygame.sprite.Sprite):
        def __init__(self, image, pos):
            super().__init__()
            self.image = image
            self.rect = image.get_rect(center=pos)
    

    Instead, it becames simpler, because we can let pygame handle blitting the image to the screen.

    So, to use pixel perfect collision, you can use pygame's Mask class. Use pygame.mask.from_surface to create a Mask from your Surface, and use pygame.mask.Mask.overlap to check if two masks overlap.

    It's easier to use when you use the Sprite class, since you could just use functions like spritecollide together with collide_mask.

    But if you don't want to use the Sprite class, just take a look how collide_mask is implemented to see how you can use masks:

    def collide_mask(left, right):
        xoffset = right.rect[0] - left.rect[0]
        yoffset = right.rect[1] - left.rect[1]
        try:
            leftmask = left.mask
        except AttributeError:
            leftmask = from_surface(left.image)
        try:
            rightmask = right.mask
        except AttributeError:
            rightmask = from_surface(right.image)
        return leftmask.overlap(rightmask, (xoffset, yoffset))