Jump to content

P2 - two flat edges colliding trigger multiple callback collisions for a "single" collision


Recommended Posts

So I've been getting a problem with my P2 player sprite, where it triggers the collision callback two or three times, for a single collision.


Basically, when to Flat Edges collide, its firing the collision callback twice



You can replicate it by editing the "collision groups" master example


First, modify the "hitPanda" method so we can see a hit count that increments with every collision callback:

hitCount = 0;function hitPanda(body1, body2) {    // body1 is the space ship (as it's the body that owns the callback)    // body2 is the body it impacted with, in this case our panda    // As body2 is a Phaser.Physics.P2.Body object, you access its own (the sprite) via the sprite property:    body2.sprite.alpha -= 0.1;        hitCount++    console.log("hitCount=" + hitCount);}

Then modify the Ship's body to something non-circle, non-pointy, like 1 or 2 or 3 below:

    game.physics.p2.enable(ship, true); //true so we can see the physics body    //ship.body.setCircle(28);1.  ship.body.addPolygon(null, 0,0, 50,0, 50,50, 0,50); //simple square2.  ship.body.setRectangleFromSprite();3.  ship.body.setRectangle(50,50);

Then, when you collide the ship into a panda, you very often get a double collision. The callback fires twice.


Initially I thought it might be a problem with using a polygon body, as that's what I have in my current WIP.

But setRectangle has the same problem. Then I thought it was the rotation, causing a tiny second hit as an objects start to rotate next to each other.

And that would have explained why a circle worked ok in the example, because when it rotates it not going to hit anything twice.


So I disabled all the rotation:

panda.body.fixedRotation = true;ship.body.fixedRotation = true;

But that didn't help.


I think I've finally found the answer via the humble triangle. Here's a pic to better explain.


- When I jab a panda with the right-side pointy end, I don't get the multiple hits. Just get a nice clean 1 hit.

- Slap into a panda with the left-side flat edge. The Panda have rectangle bodies also. When the two flat edges hit together, bingo, two collision callbacks instead of one.






Here's the triangle body code:

ship.body.addPolygon(null, 0,0, 50,25, 0,50); //triangle with a point on the right side and flat edge on the left side.//btw, set pandas to show their body:panda.body.debug = true;

So.... how to fix this issue?


(I've attached my testing code with the .txt extension added to allow it to be attached to this post)

collision groups.js.txt

Link to comment
Share on other sites

Hmmm it is when you only want a collision callback to execute once. Right now I've had to put in a 100ms timer based switch to filter out the second and third callbacks (I'm not sure its working perfectly either).

As a very simple example, imagine a game where every crash deducts a point or health. Well this bug will mean the crash gets penalised twice.

Link to comment
Share on other sites

Nice. Just tested in the example. Removed the collisionGroups stuff, and just using ship.body.onBeginContact.add(...) method, and its working as expected. Just the single hit, even with two flat edges colliding. That will have to do.


EDIT: dang.... just tried it in my game, no good. It does seems a bit more reliable, but still getting double/triple hits

Link to comment
Share on other sites


That part's easy. Just pass in the object you want as the second parameter when defining the callback function. The second param is the context, it will be accessible as the "this" object in the function.

    ship.body.onBeginContact.add(hitPanda2, ship);    //pass in "ship" as second param here,                                                       //to make it available as the "this" object when function hitPanda2 executes. 

So then over in "hitPanda2" function, I can for example access the ship's name via this.name

function hitPanda2(body2, shapeA, shapeB, equation) {    //This callback is sent:     //body2     the Body it collides with    //shapeA    the shape in the calling Body involved in the collision    //shapeB    the shape in the Body it hit    //equation  an array with the contact equation data in it    //    //this      the Ship sprite I chose to pass as the context for this function	    body2.sprite.alpha -= 0.1;    console.log(this.name);}
Link to comment
Share on other sites

@Rudy   THANK YOU so much... i was searching for this for days...     rich said "onbegincontact" is better because calculating impact events (collisiongroups and callbacks) is very expensive and we should not use them until absolutely necessary.. now i can change everything and see if the performance on mobile will finally be acceptable...

Link to comment
Share on other sites

No luck. Same deal, you just get two end contact events. I'm playing around with some ideas on how to short circuit the secondary collision. Its a bit hit and miss though and I'd like to avoid a timer approach is possible. Frustrating, I think I might work on the Player States pattern I've been meaning to get around to. It should at least clean up my code, perhaps I'll have some inspiration from that...

Link to comment
Share on other sites

  • 2 weeks later...
I think that Phaser uses the p2 impact event internally, which fires once per *contact point*, not per *body pair*. If you get two contact points, you will get two events. I agree this is a bit weird and I might even change to the less weird behavior in future p2 versions.
However, you can keep track of the body pairs yourself and prevent duplicates by looking at the body id's. Something like this will print the body id's. Do it and you'll see what I mean.
function hitPanda(body1, body2) {    console.log(body1.data.id, body2.data.id)

The two numbers are unique per body collision. During one frame, make sure the current number combination didn't occur more than once.



Link to comment
Share on other sites


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...