Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pixel perfect collision detection #216

Open
ericclack opened this issue Jan 10, 2020 · 7 comments
Open

Add pixel perfect collision detection #216

ericclack opened this issue Jan 10, 2020 · 7 comments
Labels
enhancement New feature or request

Comments

@ericclack
Copy link

ericclack commented Jan 10, 2020

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

@lordmauve
Copy link
Owner

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.

@ericclack
Copy link
Author

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.

@lordmauve
Copy link
Owner

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.

@ericclack
Copy link
Author

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.

@lordmauve
Copy link
Owner

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

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

@ericclack
Copy link
Author

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.

@lordmauve
Copy link
Owner

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 lordmauve added the enhancement New feature or request label Jan 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants