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

Create Sprite Body From ONLY Non-Transparent Pixels of an Image #5081

Closed
JimLynchCodes opened this issue Apr 6, 2020 · 7 comments
Closed

Comments

@JimLynchCodes
Copy link

We're constantly trying to make Phaser 3 better

Suppose I have an image of a ball (or anything non-rectangular, really). I export the ball image as a png with a transparent background.

I then load the image into Phaser and create a sprite from it:

this.load.image('ball', '../assets/ball.png')
this.physics.add.sprite(0, 0, 'ball')

The physics "body" that is created from this is the bounding rectangle of the ball which makes collision detection pretty wonky. I am proposing that the physics body be generated by ONLY the non-transparent pixels of the image. The advantage of this is that there will be pixel-perfect collision detection between sprites.

To me it seems obvious that it should be like this so i am wondering why it is not the default.

  • Is it especially difficult or inefficient to look access the transparency of the image and generate the physics body this way?

  • Is this currently possible and I'm just not aware of the api? (I asked about this in a forum post here and naively assumed the lack of an answer meant it wasn't really possible with the current api).

I think this would be a great feature Phaser if it doens't already exist!

Note: I may be using the wrong term "Sprite" here where possibly I mean "GameObject" since I would expect this feature to be true for any collidable thing regardless of whether it is animatable or not.

Do you want to help provide this feature?

Yes, although I don't know much about how Phaser works under the hood.

I was trying to dig through the code to see how the ".body" property was created for sprites, and couldn't really find it. I see it referenced here and here, but where is the main logic for how the sprite's body is determined? 🤔

@photonstorm
Copy link
Collaborator

This issue has been mentioned on Phaser. There might be relevant details there:

https://phaser.discourse.group/t/collisions/2065/8

@JimLynchCodes
Copy link
Author

thanks @photonstorm! Yes, that is the forum post that I linked to when I created this issue! :)

Sadly, there wasn't really a good solution. Someone recommended using a weird image editor that draws lines around your image and then exports that as a texture...

That seems like a ton of unnecessary extra work to me. Let's consider my original idea of just generating the texture from the non-transparent pixels. Is that not possible?

@hexus
Copy link
Contributor

hexus commented Apr 7, 2020

It's likely better for your game to prepare assets like this at build time, rather than at runtime, and use a physics engine like Matter.js to bring them to life. Phaser 3 doesn't have a pixel-perfect physics engine to use out of the box.

This could be made easier for you with a tool like PhysicsEditor. Here is a relevant tutorial that may help:

@JimLynchCodes
Copy link
Author

Thanks @hexus, but I don't see why Phaser can't do this out of the box.

I don't think it requires a whole "physics engine" (which phaser already has).

Rather, it just requires a small texture-generator that only needs to look at the the alpha value of each pixel of the image.

I'm wiling to help to implement this in the phaser framework so that we don't need extra editors like this! ♥️

@JimLynchCodes
Copy link
Author

@hexus @photonstorm - I tried using matter within phaser, but it seems to have very poor integration. Changing the physics from arcade to matter basically means you need to completely rewrite your game using matter.js api, and at that point is there really any point in using phaser at all?

I would really like to use the normal phaser arcade apis for things like collision detection and the actual physics of the objects moving around.

All I'm asking for is sprite bodies based on the image rather than the bounding box. Can someone please explain to me why this is so difficult for the framework itself to do?

@hexus
Copy link
Contributor

hexus commented Apr 8, 2020

A physics engine handles collision detection and responses between physics bodies, which indeed means calculating whether they've collided at all, not just what to do after they have.

Arcade, specifically, is a simple physics engine by design. No rotation and no complex shapes, only rectangle and circle intersections. This allows its collision detection and resolution to be very fast, because it can make a lot of assumptions about particular shapes and use dedicated routines for those shapes.

Matter has many more capabilities, and as a result is more expensive CPU-wise, with a bigger API surface. While I agree that it would be nice for Phaser to offer a common API across both, there's only so far something like this can go before you start needing to delve into the specifics of each engine. This is why choosing the right physics engine for a game is such an important decision, unless you're willing to write your own abstraction for your own needs (I have done this in one of my own projects).

All of that said, even I've written plugins that augment how collision detection and responses work in both engines. While neither of these were trivial, I can imagine a plugin that implements pixel-perfect collision checks in a similar way.

While it might be possible to implement pixel-perfect collision detection as part of Phaser, here are some of the main reasons I can think of that it hasn't been done yet:

  1. Arcade physics was designed to be simple and fast
  2. Matter.js is complex enough that we wouldn't want to change its behaviour other than for optimisation
  3. Pixel-perfect collision detection as you're asking for it is not trivial to implement with good performance in mind, even though your use case may simple enough that performance scaling doesn't matter to you

Pixel-perfect collision detection can be implemented either by scanning overlapping pixels between two images at run time (this can even be done on a GPU), or generating geometry that fits the artwork perfectly and colliding that geometry instead of checking pixels each frame. The former becomes considerably more expensive as the number of pixels colliding grows, and the latter becomes more expensive as artwork size grows, the geometry potentially far more complex than it may need to be for a certain game or use case.

On top of this, the non-transparent pixels of an image might not be the only ones a developer would want to detect collisions with. A developer might want to provide a pixel-perfect collision map, instead using specific colours to indicate colliding or non-colliding pixels.

I'd reconsider whether you need pixel-perfect collisions specifically, and why you can't just use a physics engine that supports more complex shapes with good tooling around it. It seems, though, that you were just hoping that Phaser itself had a solution for this out of the box. Are there many other game frameworks that do?

It would be great for @photonstorm to expand on this, because this is just my perspective here.

@photonstorm
Copy link
Collaborator

There are absolutely no plans for pixel-perfect collision detection for physics in Phaser 3, sorry. It's next to impossible to do accurately (it's not as simple as detecting if two pixels touch, or not, it's the resolution step that is the nightmare). Never mind the cost of comparing pixels, which is far worse than you'd expect it to be given all the CPU power we have these days.

Even the team at Scirra (the ones behind Construct) completely gave up on this approach years ago because it's so flawed, and just use a rigid body system now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants