How to Break Constraints with Force in Matter.js
Matter.js does not feature a native breakable joint setting, but you can programmatically break constraints under force by monitoring the tension or displacement between connected bodies during the engine's update cycle. By attaching an event listener to the engine and removing the constraint from the physics world once a predefined stretch or force threshold is exceeded, you can reliably simulate snapping ropes, breaking chains, or destructible joints.
The Approach: Measuring Strain via Hooke's Law
Matter.js constraints act like springs. While the engine resolves positional corrections iteratively and does not expose a direct force scalar on the constraint object, the force applied is directly proportional to how much the constraint has stretched beyond its resting length (\(F = k \cdot \Delta x\)).
To break a constraint under high force, calculate the distance between the two anchor points at each tick. If the absolute difference between this distance and the constraint's resting length exceeds your break limit, remove the constraint from the composite.
Implementation Example
The most reliable place to evaluate and break constraints is inside
the beforeUpdate or afterUpdate event
loop:
const { Engine, Render, Runner, Bodies, Composite, Constraint, Vector, Events } = Matter;
// 1. Create engine and world
const engine = Engine.create();
const world = engine.world;
// 2. Create two bodies
const bodyA = Bodies.rectangle(400, 200, 50, 50, { isStatic: true });
const bodyB = Bodies.rectangle(400, 350, 50, 50);
// 3. Create a constraint
const restingLength = 100;
const breakThreshold = 30; // Maximum allowed stretch in pixels
const joint = Constraint.create({
bodyA: bodyA,
bodyB: bodyB,
length: restingLength,
stiffness: 0.8
});
Composite.add(world, [bodyA, bodyB, joint]);
// 4. Listen for engine updates to check tension
Events.on(engine, 'afterUpdate', () => {
if (!joint) return;
// Determine current positions of the constraint's connection points
const pointA = joint.bodyA
? Vector.add(joint.bodyA.position, joint.pointA)
: joint.pointA;
const pointB = joint.bodyB
? Vector.add(joint.bodyB.position, joint.pointB)
: joint.pointB;
// Calculate current distance between anchors
const currentDistance = Vector.magnitude(Vector.sub(pointA, pointB));
const stretch = Math.abs(currentDistance - joint.length);
// Break the constraint if the stretch exceeds the threshold
if (stretch > breakThreshold) {
Composite.remove(world, joint);
}
});Considerations for Dynamic Joint Breaking
- Stiffness Scaling: If
stiffnessis set to1, Matter.js will aggressively resolve the distance in fewer iterations, making the stretch value smaller and harder to detect. For realistic breakable mechanics, use a stiffness slightly below 1 (e.g.,0.7to0.9) so measurable strain occurs under heavy loads. - Anchor Offsets: Always account for
joint.pointAandjoint.pointBoffsets relative to body centers. Computing the world coordinates of both points guarantees accurate distance calculations regardless of body rotation. - Multiple Breakable Joints: When managing many
breakable constraints, store them in an array and iterate through the
list on each
afterUpdatetick, splicing out any broken constraints to avoid redundant calculations.