How to use pixel perfect collision with two images pygame

1k Views Asked by At

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)

1

There are 1 best solutions below

0
sloth On BEST ANSWER

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