How to Weld Two Bodies Dynamically in Matter.js
This article explains how to dynamically weld two physics bodies together at runtime in Matter.js without reconstructing them into a compound body. By using multiple rigid constraints with spatial offsets, you can lock the relative translation and rotation between existing bodies on the fly, avoiding the performance penalties, body recreation overhead, and reference invalidation associated with rebuilding compound bodies.
Why Avoid Compound Bodies at Runtime
Creating compound bodies in Matter.js using
Body.create({ parts: [...] }) requires defining all parts
during initialization. Merging existing dynamic bodies into a compound
body during runtime forces you to destroy the original bodies, calculate
new centers of mass, and recreate new references. This resets
velocities, collision listeners, and custom state variables attached to
those bodies.
Using constraints allows both bodies to maintain their independent identities, properties, and collision filters while moving as a single rigid unit.
The Dual-Constraint Technique
A single Matter.Constraint acts as a pivot joint,
locking linear distance between two points while allowing free angular
rotation. To completely weld two bodies and prevent both linear movement
and rotation, you must create at least two parallel constraints with
offset anchor points.
Implementation
To weld Body A and Body B at their current relative positions,
calculate local offset anchors and connect them using two constraints
with a stiffness of 1 (or close to
1 depending on engine iterations).
const { Constraint, Composite, Vector } = Matter;
function weldBodies(world, bodyA, bodyB) {
// Define an offset distance for the dual anchor points
const offset = 20;
// Calculate local anchor positions on Body A
const pointA1 = { x: -offset, y: 0 };
const pointA2 = { x: offset, y: 0 };
// Convert Body A local points to world coordinates
const worldPoint1 = Vector.add(bodyA.position, Vector.rotate(pointA1, bodyA.angle));
const worldPoint2 = Vector.add(bodyA.position, Vector.rotate(pointA2, bodyA.angle));
// Convert world coordinates to Body B's local coordinate space
const pointB1 = Vector.rotate(Vector.sub(worldPoint1, bodyB.position), -bodyB.angle);
const pointB2 = Vector.rotate(Vector.sub(worldPoint2, bodyB.position), -bodyB.angle);
// Create two rigid constraints connecting the calculated anchor pairs
const constraint1 = Constraint.create({
bodyA: bodyA,
pointA: pointA1,
bodyB: bodyB,
pointB: pointB1,
length: 0,
stiffness: 1
});
const constraint2 = Constraint.create({
bodyA: bodyA,
pointA: pointA2,
bodyB: bodyB,
pointB: pointB2,
length: 0,
stiffness: 1
});
// Add the constraints to the physics world
Composite.add(world, [constraint1, constraint2]);
return [constraint1, constraint2];
}Breaking or Releasing the Weld
To separate welded bodies, remove the constraints from the world composite:
function unweldBodies(world, constraints) {
Composite.remove(world, constraints);
}Once the constraints are removed, both bodies instantly resume independent physical behavior, maintaining any momentum transferred during their welded state.
Ensuring Weld Rigidity
Matter.js resolves constraints iteratively. If the weld exhibits minor bending or elasticity under heavy forces:
- Increase Constraint Iterations: Raise
engine.constraintIterations(default is2) to4or8in your engine configuration to reduce joint compliance. - Increase Anchor Separation: Wider spacing between
pointA1andpointA2provides greater leverage against rotational forces, significantly reducing visible flexing.