Continuous Collision Detection in Matter.js

Continuous Collision Detection (CCD) is designed to prevent fast-moving bodies from passing through obstacles without triggering a collision, an issue known as tunneling. Matter.js, a popular 2D physics engine for the web, does not feature an automated, built-in swept CCD solver like some heavier physics engines. Instead, Matter.js natively relies on discrete collision detection using the Separating Axis Theorem (SAT), requiring developers to employ specific architectural strategies, such as engine sub-stepping, raycasting, and geometry adjustments, to achieve continuous collision behavior.

The Problem of Discrete Detection and Tunneling

In standard Matter.js updates, the physics engine calculates object positions frame by frame based on their velocity and the elapsed delta time. If a body moves at a high speed or the frame rate drops, the distance traveled in a single tick can exceed the thickness of another object or wall. Because Matter.js samples overlap strictly at the end of each discrete step, the body can jump completely from one side of an obstacle to the other without an intersection ever being registered.

Achieving CCD via Sub-Stepping

The primary way to simulate continuous collision detection in Matter.js is through sub-stepping. Rather than advancing the engine by a single large time step per render frame (e.g., 16.6ms for 60 FPS), you split the update into multiple smaller intervals:

  1. Manual Sub-Step Loop: Instead of letting Matter.Runner automatically advance the engine with a single delta, you can disable the default runner and advance the engine multiple times inside your render loop (e.g., calling Matter.Engine.update(engine, delta / subSteps) four to eight times per frame).
  2. Reduced Displacement: By reducing the time delta per calculation, the displacement per step shrinks significantly, ensuring that fast-moving bodies overlap with barriers rather than skipping through them.
  3. Solver Iterations: Adjusting engine.positionIterations and engine.velocityIterations improves the precision of the contact resolution, though iterations alone do not resolve tunneling without smaller step deltas.

Trajectory Raycasting Using Matter.Query

For extremely fast, small projectiles (like bullets), sub-stepping can become computationally expensive. A more performant approach to CCD in Matter.js is predictive raycasting:

Environmental Geometry Adjustments

Another practical method to prevent tunneling without code overhead is modifying the physical properties of the environment: