How to Find Collision Impulse in Matter.js
This article explains how to determine the impulse applied to bodies during a collision in the Matter.js 2D physics engine. Matter.js calculates linear and angular impulses internally to resolve penetrations and bounce bodies apart. By intercepting collision events and inspecting the internal properties of collision pairs—or by measuring the resulting change in momentum—you can accurately measure the force of impact for damage calculations, sound triggering, or custom game logic.
Method 1: Reading Impulses from Collision Contacts
Matter.js tracks contact points between colliding pairs and calculates the normal and tangential impulses during the collision resolution step. Each collision pair contains a list of contact points, each holding its resolved impulse values.
Because impulses are applied during the collision solve step, they
are fully populated in the collisionActive event or in an
afterUpdate listener immediately following
collisionStart.
Matter.Events.on(engine, 'collisionActive', (event) => {
event.pairs.forEach((pair) => {
let totalNormalImpulse = 0;
let totalTangentImpulse = 0;
pair.contacts.forEach((contact) => {
// normalImpulse represents the direct impact force
totalNormalImpulse += contact.normalImpulse || 0;
// tangentImpulse represents the frictional impulse along the surface
totalTangentImpulse += contact.tangentImpulse || 0;
});
// Combined magnitude of the impulse applied this frame
const totalImpulse = Math.hypot(totalNormalImpulse, totalTangentImpulse);
if (totalImpulse > 0) {
console.log(`Impulse between ${pair.bodyA.label} and ${pair.bodyB.label}:`, totalImpulse);
}
});
});Method 2: Calculating Impulse via Change in Momentum
If you require the impulse magnitude directly at
collisionStart before the internal contact impulses are
updated, or if you want a physics-agnostic value, you can calculate the
impulse using the impulse-momentum theorem:
\[\vec{J} = m \Delta \vec{v} = m (\vec{v}_{\text{after}} - \vec{v}_{\text{before}})\]
To do this:
- Record each body's velocity in the
beforeUpdateevent. - In the
afterUpdateevent, compare the recorded velocity to the new velocity for any bodies that collided.
const preVelocities = new Map();
// 1. Store velocities before collisions are solved
Matter.Events.on(engine, 'beforeUpdate', () => {
engine.world.bodies.forEach((body) => {
preVelocities.set(body.id, { x: body.velocity.x, y: body.velocity.y });
});
});
// 2. Measure the delta after collisions are resolved
Matter.Events.on(engine, 'afterUpdate', () => {
// Alternatively iterate through engine.pairs.list
engine.world.bodies.forEach((body) => {
if (body.isStatic) return;
const pre = preVelocities.get(body.id);
if (!pre) return;
const deltaVx = body.velocity.x - pre.x;
const deltaVy = body.velocity.y - pre.y;
const deltaV = Math.hypot(deltaVx, deltaVy);
// Impulse magnitude: J = mass * deltaV
const impulse = body.mass * deltaV;
if (impulse > 0.1) {
// Body experienced an external impulse
console.log(`Body ${body.id} experienced an impulse of:`, impulse);
}
});
});Key Differences Between Methods
- Contact Points
(
contact.normalImpulse): Best when you need isolated force data specifically for the interface between two specific bodies. This excludes other external forces like gravity or engine-level damping. - Momentum Change (\(m \Delta v\)): Best for determining the overall physical impact experienced by a single body in a frame, regardless of how many simultaneous contacts occurred.