pgzero icon indicating copy to clipboard operation
pgzero copied to clipboard

Add pixel perfect collision detection

Open ericclack opened this issue 5 years ago • 7 comments

Hi, many thanks for creating Pgzero, it's working really well at our Coder Dojo in Brighton :)

I've hacked together some code for pixel perfect collision detection, would you consider adding it to pgzero? I can submit a pull request if you are happy to review.

Here's the code:

def collide_pixel(actor1, actor2):

    # Get masks for pixel perfect collision detection:
    for a in [actor1, actor2]:
        if not hasattr(a, 'mask'):
            a.mask = mask.from_surface(a._orig_surf)

    # Offsets based on current positions of actors
    xoffset = int(actor2.left - actor1.left)
    yoffset = int(actor2.top - actor1.top)

    # Check for overlap = collision
    return actor1.mask.overlap(actor2.mask, (xoffset, yoffset))

Bit more background here: http://chalkpath.co.uk/blog/html/2020/01/12/pixel_perfect_collision_detection_with_pygamezero.html

ericclack avatar Jan 10 '20 20:01 ericclack

I don't think pixel perfect collision detection by checking mask intersections is a good idea to put into Pygame Zero. It's not a good lesson to teach because it's too slow for general purpose use in games. That's not to say it has no uses at all. It vectorises well, and could be GPU accelerated (but not in Pygame). However, the point is that you'd have to carefully choose where to apply it to get the benefit of it.

Perhaps Pygame Zero should offer collision detection features, but I'd want it to be via quadtrees and polygon intersection tests, not pixel masks.

lordmauve avatar Jan 11 '20 00:01 lordmauve

Thanks for your feedback.

Here's one of the use-cases for better-than-rect collision detection: a maze game where the coder draws the walls and the whole maze is rendered as a single image: https://scratch.mit.edu/projects/11710850/editor/

In this case the coder doesn't use mask collision detection but something more like 'pixel colour at location'.

What are your thoughts on how to achieve this with Pgzero? I can see that we could get the coder to draw the maze with individual sprites for each wall and use colliderect on them, but that would be a lot of work.

ericclack avatar Jan 11 '20 15:01 ericclack

In a maze with walls like that, you don't really want free movement, because that will create quite a fiddly experience.

Maybe I should write an example game to show how best to write something like that.

lordmauve avatar Jan 15 '20 09:01 lordmauve

Well I'd be happy to explore too. If you want to give me some pointers, things you'd explore first, I'll have a go.

ericclack avatar Jan 19 '20 23:01 ericclack

I wrote an example game; let me know what you think:

https://github.com/lordmauve/pgzero/tree/master/examples/maze/

lordmauve avatar Jan 20 '20 11:01 lordmauve

That's an interesting example, I like the maze generation code and I can see how you've redone the collision detection to avoid moves that are not possible.

Going back to the original question I asked "can we have pixel perfect collision detection in Pgzero?" I think the answer is: you probably don't need it, generate the world using sprites or data structures so that you can check for collisions in a way that's more efficient than checking pixels.

If we do decide to use it occasionally do you think my method collide_pixel above is relatively safe? It is poking about in the Pygame internals, e.g. using _orig_surf, which is why I ask.

ericclack avatar Jan 21 '20 13:01 ericclack

If we do decide to use it occasionally do you think my method collide_pixel above is relatively safe? It is poking about in the Pygame internals, e.g. using _orig_surf, which is why I ask.

No, you're right _orig_surf might change. However, you can always get a surface with images.load(name). So if the Actor's .image attribute is a string, it would be

mask.from_surface(images.load(actor.image))

Going back to the original question I asked "can we have pixel perfect collision detection in Pgzero?" I think the answer is: you probably don't need it, generate the world using sprites or data structures so that you can check for collisions in a way that's more efficient than checking pixels.

Exactly. I think we probably need a documentation section that talks about game maths, algorithms and datastructures, including collision detection. It's on my to-do list.

lordmauve avatar Jan 21 '20 15:01 lordmauve