2
\$\begingroup\$

I'm using LibGDX with Box2D and, when two bodies collide, the collision is detected multiple times.

Here's the code:

public void preSolve(Contact contact, Manifold oldManifold)
{
  Body a = contact.getFixtureA().getBody();
  Body b = contact.getFixtureB().getBody();

  if ((Utils.IsPlayer(a) && Utils.IsEnemy(b)) || 
      (Utils.IsEnemy(a)  && Utils.bodyIsPlayer(b)))
  {
    player.isHit = true;
    player.destroy();
    System.out.println(player.isHit);
  }
}

The player is destroyed multiple times; I want the player to be destroyed only once.

\$\endgroup\$
  • \$\begingroup\$ When two bodies collide, it's likely that there are many contacts to resolve that's why you're seeing more than one collision I think. What data do you need from the collision? Do you just need to know that they have collided or do you need to know the forces involved in the collision? \$\endgroup\$ – bornander Jun 29 '15 at 7:29
  • 1
    \$\begingroup\$ An example of where you're seeing duplicate collisions would be most helpful. \$\endgroup\$ – NauticalMile Jun 30 '15 at 0:14
  • 2
    \$\begingroup\$ If your problem is that when eg. objects A and B collide, you get one event for the A-against-B collision and one event for the B-against-A collision: assign every game object a unique ID and only process events where A.id >= B.id. That's a general approach to duplicate filtering in pairwise event scenario's. \$\endgroup\$ – Jelle van Campen Jul 31 '15 at 16:49
2
\$\begingroup\$

I recommend you look into how box2D works.

Anyways use one of the below, most likely BeginContact.

void BeginContact(b2Contact* contact);
void EndContact(b2Contact* contact);

Excerpt from the from the greatest source of Box2d knowledge know to mankind to explain why.

iforce2d.com: Anatomy of a collision


Impact 1, 2, 3

enter image description hereenter image description hereenter image description here

When fixtures are overlapping, Box2D's default behavior is to apply an impulse to each of them to push them apart, but this does not always succeed in a single time step. As shown here, for this particular example the two fixtures will be overlapping for three time steps before the 'bounce' is complete and they separate again.

During this time we can step in and customize this behavior if we want to. If you are using the contact listener method, the PreSolve and PostSolve functions of your listener will be repeatedly called in every time step while the fixtures are overlapping, giving you a chance to alter the contact before it is processed by the collision response (PreSolve) and to find out what impulses were caused by the collision response after it has been applied (PostSolve).

To make this clearer, here is the output obtained for this example collision by putting a simple printf statement in the main Step function and each of the contact listener functions:

...
Step
Step
BeginContact
PreSolve
PostSolve
Step
PreSolve
PostSolve
Step
PreSolve
PostSolve
Step
EndContact
Step
Step
...

Outcome: PreSolve and PostSolve are called repeatedly

\$\endgroup\$
0
\$\begingroup\$

Firstly, your question is very unclear. It doesn't have all the necessary information. Nothing at all in fact. Try to be a little more informative or precise in the future.

When two bodies collide in Box2D there are numerous collisions. Collisions in Box2D are really the fixtures which are used to detect when a collision occurs.

Collisions can happen in all kinds of ways so they have a lot of information that can be used in the game logic.

An object named 'b2Contact' has information of the list of colissions occuring. This is how you can access that list.

 for (b2Contact* contact = world->GetContactList(); contact; contact = contact->GetNext())
  contact->... //do something with the contact

or you can make use of collision listeners. Also, these kinds of collisions and lists state the collisions with the AABBs meeting. And if you wish to know if the fixtures itself are meeting, you can use IsTouching() method.

\$\endgroup\$
  • \$\begingroup\$ You're right the question is vague, I added more information on the question. \$\endgroup\$ – Ray Jul 1 '15 at 6:18
  • \$\begingroup\$ Not as an attack, but in general, SE would prefer you post comments about questions in the question's comments section because comments about the question are, by-definition, not answers to the question. Once the answer is improved, your comment is invalid. When the topic is visited in the future, only the most-current version is shown, not the full back-story. The future visitor considers the question very well-formed and wonders what in the world you're talking about. This could, depending on the comment, affect people's confidence in your answer and/or affect the votes that you receive. \$\endgroup\$ – Jon Feb 28 '16 at 23:19
  • \$\begingroup\$ If you know what they meant to ask, say so in comment and pre-answer that question, instead. If they, indeed, meant what you thought they did, not only will your answer still get up-votes, even if they ignore you or make the question even worse, but your comment become eligible of its' own up-votes. It's a win/win for you. \$\endgroup\$ – Jon Feb 28 '16 at 23:29
0
\$\begingroup\$

For many collisions, there will be several contacts to resolve. This is why you're getting multiple calls to your player.destroy().

I don't know what you're doing in the destroy method, but you shouldn't destroy any Box2D bodies of fixtures in there, as they might be needed for other preSolve calls.

What you could do is instead of immediately destroying the player when the Contact is solved, set a pending destruction flag on the player (in your case the isHit member might work for you;

public void preSolve(Contact contact, Manifold oldManifold) {
  Body a = contact.getFixtureA().getBody();
  Body b = contact.getFixtureB().getBody();

  if ((Utils.IsPlayer(a) && Utils.IsEnemy(b)) || (Utils.IsEnemy(a) && Utils.bodyIsPlayer(b))) {
    player.isHit = true;
  }
}

Then in your update method (possibly the Screen.render method or where ever you handle what you need to do in your game loop), you read the flag and destroy the player then. Destroying Box2D bodies in callbacks like preSolve is likely to cause Box2D to crash.

\$\endgroup\$
0
\$\begingroup\$

It's totally possible for multiple collisions to occur in your situation. What you can do is to check for the first time that happens, and then destroy your player only once.

You can then disable collision detection for the player after that to prevent the 2nd, 3rd or more collisions from occurring anymore.

You can also check to see if the player is destroyed before attempting to destroy it again.

There are so many ways of going about doing this :)

\$\endgroup\$
0
\$\begingroup\$

I was searching for an answer because I had the exact same problem, and I thought of a great and light workaround. When you create your method of what happens to your B2D Body after the collision, just create an object and assign it to the obects' .getUserData. Then when the collision is called again, you can "save yourself" with an "if statement".Example:

public void onHit() {
    if (object != body2.getUserData()){
        setToDestroy = true;
    object = body2.getUserData();

}

It actually worked for me!

\$\endgroup\$
0
\$\begingroup\$

If one of the body has two (or more) fixtures, then the touch event will occur several times. You check it in preSolve.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.