Box 2D 2.1a Tutorial – Part 6 (Collision strength)

Today, we will once again be returning to the topic of collisions to answer a request which was, “how to determine the strength involved in a collision”. By gaining access to this information, we can then decide when to implement sound effects, damage modeling, score, etc.

Currently, we have been using the b2ContactListener for detection of when a collision occurs by overwriting the BeginContact function and accessing the b2Contact parameter. However, you will notice that the b2Contact does not offers us anything for determining the forces involved in a collision.

The secret is that we need to make use of another function of the b2ContactListener, the PostResolve function, which is called after collision detection and resolution has occurred. By overwriting this, not only do we get access to a b2Contact parameter, but we can also gain access to a b2ContactImpulse parameter.
The b2ContactImpulse has two fields of interest. The normalImpulses and tangentImpulses, both of type Vector. A quick look in the Box2D manual reveals their purpose:

  • normal impulse
    The normal force is the force applied at a contact point to prevent the shapes from penetrating. For convenience, Box2D works with impulses. The normal impulse is just the normal force multiplied by the time step.
  • tangent impulse
    The tangent force is generated at a contact point to simulate friction. For convenience, this is stored as an impulse.

So it would seem normal impulse is what we are after. My understanding is the force to prevent shapes overlapping is going to be equal to the force causing it to overlap in the first place.

Thus for each contact, we will receive a Vector of normalImpulses. However, from my tests, it seems only the first value is of any use, with the second value seemingly to always be 0 (in saying so, there is probably a case where this won’t be true). We can then use this value to determine the magnitude of the force and use this however we please. In my asteroids demo, I simply check to see if this value is above a threshold, and if it is, I mark it for exploding.

package
{
	import Box2D.Dynamics.Contacts.b2Contact;
	import Box2D.Dynamics.b2ContactImpulse;
	import Box2D.Dynamics.b2ContactListener;

	public class AsteroidContactListener extends b2ContactListener
	{
		override public function PostSolve(contact:b2Contact, impulse:b2ContactImpulse):void
		{
			if(impulse.normalImpulses[0] > 70)
			{
				if(contact.GetFixtureA() != null)
				{
					var asteroidOne:Asteroid = contact.GetFixtureA().GetBody().GetUserData();
					asteroidOne.collide = true;
				}
				if(contact.GetFixtureB() != null)
				{
					var asteroidTwo:Asteroid = contact.GetFixtureB().GetBody().GetUserData();
					asteroidTwo.collide = true;
				}
			}
		}
	}
}

Full zipped source (with limited artwork)

  • Joe

    sweet!! i’m looking forward to getting to this part of the tuts :D
    keep ‘em coming!

  • Padilla Esteban

    Very well done, there are not enough tutorials available for Box2D.
    Please continue.

    Thank you.
    EPadilla

  • SticksStones

    Brilliant! I spent days trying and failing to figure this out!

    Thanks Allan!

  • Stoyan

    Hello!
    This is really nice series of tutorials. Very helpful.
    I have a question…
    I have a ball – dynamic body which is moving. In the same time I have a second body again with circle shape but static.
    What I want to make is to apply a force (or impulse) to the ball when both objects collide.
    Following you tutorials I know how to detect collision between the two bodies so I know when to apply the force but I don’t know how to apply this force realistically.
    Lets say I want to apply an impulse (0, -1). I put this in PostSolve:
    ball.ApplyImpulse(new b2Vec2(0, -1), new b2Vec2(player.GetPosition().x, player.GetPosition().y));

    The problem is that it doesn’t look realistically most of the time. I know that I have to correct the impulse with the contact point value or maybe with the b2ContactImpulse but I am not sure how?

    Can you help me with this.
    Thanks in advance.

    BTW I don’t really understand the difference between ApplyForce and ApplyImpulse.

  • Anonymous

    Hi :)

    What do you mean by it looks unrealistic? Is it like say a platformer, and you have a character that is supposed to bounce really high on a particular box, but there is no forward momentum with the jump? or is it something else entirely?

    As for the difference between ApplyForce and ApplyImpulse, they are fairly similar. The main difference is that Impulse = change in momentum = force x time. There is a bit more of an explanation here http://box2d.org/forum/viewtopic.php?f=3&t=260

  • Stoyan

    Hello, Thank you so much for your reply :)
    To be more clear I’ll make an example later this evening to explain better…

  • Seagull

    Hello! Thank you for great tutorials!
    Please, sorry for my English.
    I have a little question, I saw a b2ContactPoint class. Where can I use it? I want to create an explosion effect, and calculate damage by distance of explosion shape center. May I do this with b2ContactPoint.separation, or I must manualy calculate distance by contact position and explosion shape position?
    Thanks!

  • Anonymous

    Cheers :)
    It seems that b2ContactPoint is no longer used by Box2D anymore. In earlier Box2D versions the b2ContactListener function parameters were of type b2ContactPoint but are now of type b2Contact. Apart from one trivial piece of code in the Box2D engine, I can not see anywhere where it is being used. So I would assume that manually calculating the distance is the way to go.

  • Seagull

    Not good =( When I worked with Box2D C++ version, it was the only way? to work with contact points.

    Thank you=)

  • Lemayn

    Hi,
    Thanks a lot for your tutorials! They helped me out to understand how Box2D 2.1 works! This is much appreciate.

    Just a question, is it normal that this tutorial (part 6) doesn’t containt the source? I manage to destroy my asteroids on the update event, but I would like to see if I did the good way (using GetBodyList).

    Regards

  • Anonymous

    Thanks :) Yes, I did leave out the full source code but I will add it for you.