How to Create Breakable Welds in Matter.js
Creating breakable welds in Matter.js allows you to simulate destructible structures, brittle joints, and breakaway vehicle parts that snap apart under severe impacts. Because Matter.js does not have an out-of-the-box breakable constraint property, you must simulate this behavior by combining rigid constraints with collision event listeners to evaluate impact forces and remove the constraint from the physics world when a predefined threshold is exceeded.
Setting Up Rigid Welds
In Matter.js, a weld is represented by a Constraint with
a stiffness value close to 1 and an
appropriate length (typically 0 for direct body-to-body
attachments).
const { Bodies, Constraint, Composite } = Matter;
// Create two bodies to weld together
const bodyA = Bodies.rectangle(400, 300, 80, 40);
const bodyB = Bodies.rectangle(400, 340, 80, 40);
// Create the rigid weld constraint
const weld = Constraint.create({
bodyA: bodyA,
bodyB: bodyB,
pointA: { x: 0, y: 20 },
pointB: { x: 0, y: -20 },
stiffness: 1,
length: 0
});
// Custom property to define breaking force and status
weld.breakForce = 15;
weld.isBroken = false;
Composite.add(engine.world, [bodyA, bodyB, weld]);Detecting Collision Forces
Constraints in Matter.js do not natively compute dynamic stress
vectors internally. Instead, the most reliable way to snap a weld on a
heavy impact is to monitor collision events using
Events.on(engine, 'collisionStart', handler).
During a collision, you measure the impact force by evaluating the relative velocity and mass of the colliding bodies, or by checking the impulse generated across the collision pairs.
Matter.Events.on(engine, 'collisionStart', (event) => {
const pairs = event.pairs;
for (let i = 0; i < pairs.length; i++) {
const pair = pairs[i];
const { bodyA, bodyB } = pair;
// Calculate relative speed between the two colliding bodies
const relativeVelocity = {
x: bodyA.velocity.x - bodyB.velocity.x,
y: bodyA.velocity.y - bodyB.velocity.y
};
const impactSpeed = Math.sqrt(
relativeVelocity.x * relativeVelocity.x +
relativeVelocity.y * relativeVelocity.y
);
// Approximate impact force based on relative speed and reduced mass
const reducedMass = (bodyA.mass * bodyB.mass) / (bodyA.mass + bodyB.mass);
const estimatedForce = impactSpeed * (reducedMass || 1);
// Check if the collision involves welded bodies
checkAndBreakWeld(weld, bodyA, bodyB, estimatedForce);
}
});Snapping and Removing the Constraint
When the estimated collision force exceeds your defined
breakForce, remove the constraint from the active world
composite.
function checkAndBreakWeld(constraint, collidingA, collidingB, force) {
if (constraint.isBroken) return;
// Verify if either colliding body belongs to the constraint
const involvesWeld =
constraint.bodyA === collidingA || constraint.bodyA === collidingB ||
constraint.bodyB === collidingA || constraint.bodyB === collidingB;
if (involvesWeld && force > constraint.breakForce) {
// Break the weld
Matter.Composite.remove(engine.world, constraint);
constraint.isBroken = true;
}
}Managing Multiple Breakable Welds
When scaling to structures with multiple breakable parts, maintain an array of active welds and iterate through them during collision processing:
- Tag constraints: Attach an identifier or store them
in a dedicated list (e.g.,
breakableConstraints). - Batch removal: Collect all constraints that exceed their breaking thresholds during the collision loop.
- World update: Remove broken constraints using
Composite.remove(world, constraint)immediately to ensure subsequent physics solver iterations treat the bodies as disconnected.