When making games with Box2D, one natural question that arises is:

"what can we determine about the *general state* of a body
given its velocity and collision information"?

local lv = b2.Vec2(0, 0) function b2.Body:IsMoving(treshold) treshold = treshold or b2.linearSleepTolerance self:GetLinearVelocity(lv) return lv:Length() > treshold end

function b2.Body:IsRotating(treshold) treshold = treshold or b2.angularSleepTolerance local angular = self:GetAngularVelocity() return angular < -treshold or angular > treshold end

local lv = b2.Vec2(0, 0) function b2.Body:IsMovingOnAxis(ax, ay) self:GetLinearVelocity(lv) return ax*lv.x + ay*lv.y end

local wmf = b2.WorldManifold() function b2.Body:IsPushedOnAxis(ax, ay) local edge = self:GetContactList() while edge do local contact = edge.contact if contact:IsTouching() then local mf = contact:GetManifold() if mf.pointCount > 0 then contact:GetWorldManifold(wmf) local n = wmf.normal local nx, ny = n.x, n.y local other = contact:GetFixtureA():GetBody() if other ~= self then nx, ny = -nx, -ny end if ax*nx + ay*ny > 0 then return true end end end edge = edge.next end return false endOne further refinement could be to compute the total impulse acting on the body along the given axis. This can help us determine how firmly the body is being supported.

Rectangle supported by a platform. Contact points shown in white and collision normal in blue

Left: 1 contact with 1 point (vertex to edge)

Right: 1 contact with 2 points (edge to edge)

Note that it's important to consider the direction of each collision normal in order to determine if a contact is pushing the body up, down, sideways or both! One fixture can be in contact with several others, so it's possible for the poor rectangle to be "sandwiched" or pushed in opposite directions at the same time.

restitution = contact:GetRestitution()Depending on the restitution, we can categorize collisions in three types:

*Perfectly elastic* (restitution = 1)

No kinetic energy is lost so there is no sound or damage caused to the colliding objects.

Example: perfectly elastic ball that can bounce forever

*Elastic* (restitution > 0 and restitution < 1)

Some kinetic energy is converted into heat, sound or causes deformation.

Example: bouncing basketball

*Inelastic* (restitution = 0)

A lot of kinetic energy is converted into heat, sound or causes deformation.

The colliding objects remain together after the impact.

Example: ball made of soft clay that sticks to floor when dropped

Generally, momentum and energy are always conserved when dealing with a closed system. With Box2D, this is not particularly true for example when using "static" bodies with 0 restitution. Also note that, simulating deformation is beyond the scope of both Box2D and this tutorial.

As a general reference, let's look at the restitution coefficients of different types of balls:

0.858 golf ball

0.804 billiard ball

0.712 tennis ball

0.658 glass marble

0.597 steel ball bearing

velocity1 = firstBody:GetLinearVelocity() velocity2 = secondBody:GetLinearVelocity() velocityDiff = velocity1 - velocity2Next, we find how fast the two bodies are moving towards each other, given the their "difference in velocity" and position.

-- direction vector direction = firstBody:GetPosition() - secondBody:GetPosition() directionNormal = direction:Normalize() -- relative speed (in Meters per second) relativeSpeed = b2.Dot(velocityDiff, directionNormal)The resulting "relative speed" is:

The relative velocity in one dimension: two cars located at two positions (p

direction = p1 - p2

directionNormal = direction/abs(direction)

velocityDiff = v1 - v2

relativeSpeed = velocityDiff*directionNormal

The "ContactListener" class has four callbacks: "BeginContact", "EndContact", "PreSolve" and "PostSolve". Just remember that you really,

The following method should work best during the "BeginContact" or "PreSolve" callbacks,

worldManifold = b2.WorldManifold() function listener:PreSolve(contact, oldManifold) manifold = contact:GetManifold() if manifold.pointCount > 0 then firstBody = contact:GetFixtureA():GetBody() secondBody = contact:GetFixtureB():GetBody() contact:GetWorldManifold(worldManifold) -- Campbell's method contactPoint1 = worldManifold.points[1] velocity1 = firstBody:GetLinearVelocityFromWorldPoint(contactPoint1) velocity2 = secondBody:GetLinearVelocityFromWorldPoint(contactPoint1) -- velocity difference vector velocityDiff = velocity1 - velocity2 -- impact speed (in Meters per second) impactSpeed = b2.Dot(velocityDiff, worldManifold.normal)When used in the "PreSolve" callback, the result is the relative speed of the contact points at the

-- impulse restitution = 1 + contact:GetRestitution() mass = secondBody:GetMass() -- estimated impulse impulse = impactSpeed*mass*restitution -- optional: accumulate impulse impulse = impulse + oldManifold.point[1].normalImpulseAgain, remember that "impact speed" is actually the relative velocity of the

Contact points shown in white, and their velocities shown in green.

Left: with torque

Right: without torque

During the "PostSolve" callback, the body has already reacted to the collision and Box2D is reporting to us what impulses were applied. Based on the impulse information in the "b2.ContactImpulse" object, we can backtrack and find what the relative velocity was during impact:

worldManifold = b2.WorldManifold() function listener:PostSolve(contact, contactImpulse) manifold = contact:GetManifold() if manifold.pointCount > 0 then firstBody = contact:GetFixtureA():GetBody() secondBody = contact:GetFixtureB():GetBody() contact:GetWorldManifold(worldManifold) -- impulse impulse = worldManifold.normalImpulses[1] -- optional: accumulate impulse impulse = impulse - manifold.points[1].normalImpulse -- impact speed mass = secondBody:GetMass() restitution = 1 + contact:GetRestitution() -- estimated impact speed impactSpeed = impulse/mass/restitutionBasically, we divide the impulse normal by the mass (changeInVelocity = impulse/mass) and de-integrate the restitution. Note that it's a good idea to check in case the mass is zero (usually for static bodies) and avoid the division altogether. That's one way to find what the "impact speed" was (past tense) at the point of contact.

References:

Anatomy of a collision by Chris Campbell

Collision types by Joy Wagon

Coefficient of restitution by Wikipedia

The Physics Factbook by Glen Elert