How to Stop Bodies Passing Through in Matter.js
In 2D physics simulations built with Matter.js, fast-moving objects or thin boundaries often cause "tunneling," an artifact where rigid bodies pass straight through one another instead of colliding. This issue stems from discrete collision detection, which checks for intersections only at specific intervals rather than continuously. This guide outlines the most effective techniques to resolve tunneling in Matter.js, including adjusting engine solver iterations, implementing custom sub-stepping, increasing obstacle thickness, and clamping body velocities.
1. Increase Engine Solver Iterations
Matter.js uses iterative solvers to resolve collisions and constraints. By default, the engine runs a low number of iterations to conserve performance. Increasing these values makes collision resolution significantly more accurate and rigid.
Modify your engine's positionIterations and
velocityIterations:
const engine = Matter.Engine.create({
positionIterations: 10, // Default is 6
velocityIterations: 8 // Default is 4
});Raising these values forces the engine to spend more calculations resolving overlaps, preventing objects from sinking into or escaping through opposing surfaces.
2. Implement Sub-Stepping (Smaller Time Steps)
If an object moves faster than its own width in a single simulation frame, it will completely skip past a barrier without triggering a collision. The most reliable fix is to break the engine update into smaller, multiple sub-steps per frame.
Instead of running a single Matter.Engine.update per
render tick, execute multiple updates with smaller delta values:
const subSteps = 4;
const delta = 1000 / 60; // 60 FPS standard delta
function gameLoop() {
const subDelta = delta / subSteps;
for (let i = 0; i < subSteps; i++) {
Matter.Engine.update(engine, subDelta);
}
requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);Sub-stepping effectively reduces the distance a body travels between collision checks, virtually eliminating tunneling for fast-moving bodies.
3. Increase Boundary Thickness
Thin static bodies (such as lines or 1-pixel walls) are the most common victims of tunneling. A fast-moving body will easily step over thin barriers from one frame to the next.
- Make boundary walls and static obstacles significantly thicker than they appear visually.
- For boundaries off-screen, give walls a thickness of 100 to 200 pixels.
- If a visual element must remain thin, decouple the visual rendering from the physical body, or place a thick, invisible physics body behind the visible surface.
4. Clamp Maximum Body Velocity
If sub-stepping is too computationally expensive for your target platform, you can enforce a terminal velocity on fast-moving bodies. This prevents objects from ever reaching a speed that allows them to skip boundaries.
Listen to the beforeUpdate event to constrain object
speeds:
const MAX_SPEED = 15;
Matter.Events.on(engine, 'beforeUpdate', () => {
const speed = Matter.Vector.magnitude(body.velocity);
if (speed > MAX_SPEED) {
const clampedVelocity = Matter.Vector.mult(
Matter.Vector.normalise(body.velocity),
MAX_SPEED
);
Matter.Body.setVelocity(body, clampedVelocity);
}
});Summary of Best Practices
To achieve stable collisions in Matter.js:
- Combine moderately increased solver iterations
(
positionIterations: 8or10) with thicker static boundaries for general physics stability. - Use manual sub-stepping for projects featuring high-speed projectiles or fast-paced gameplay.
- Use velocity clamping as a safeguard against edge cases where extreme forces are applied.