Matter.js Broad-Phase Collision Detection Explained
In Matter.js, collision handling operates on a multi-stage pipeline
designed to maintain high performance by eliminating non-colliding
objects before running expensive geometry calculations. The
Matter.Detector.collisions method serves as the core
coordinator for this broad-phase stage, scanning registered bodies to
produce a list of active collision candidates. This article explains how
Matter.Detector.collisions identifies these candidates
through part flattening, spatial boundary evaluations, collision
filtering rules, and state optimizations.
Compound Part Extraction
Matter.js represents both simple and complex objects as bodies
composed of one or more parts. When
Matter.Detector.collisions begins its evaluation, it does
not compare composite bodies as single monolithic entities. Instead, it
accesses the flattened array of leaf parts for each body. The top-level
parent body is ignored in geometric testing if it contains subordinate
parts, ensuring that collision detection resolves at the primitive
convex polygon or circle level.
Fast State Rejection
Before running any spatial or geometric math, the detector skips pairs that cannot produce active physical responses:
- Static and Sleeping Objects: Two bodies that are both static, or both sleeping, or a combination of static and sleeping, are immediately bypassed. Because neither body is moving, their collision state cannot change.
- Self-Collision Hierarchy: Individual parts belonging to the same parent compound body are discarded immediately, preventing an entity from colliding with itself.
Collision Filtering (Masks and Categories)
Candidates that pass state checks are evaluated using bitwise
collision filters via body.collisionFilter. Each part
contains group, category, and
mask properties.
- Collision Groups: If both parts share the same
non-zero
groupvalue, positive values force an automatic collision candidate match, while negative values force an immediate rejection. - Category and Mask Bitmasks: If the group values do
not match or are zero, the detector performs a bitwise AND comparison:
If either side of the bitwise comparison evaluates to zero, the pair is discarded.
(filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0
Axis-Aligned Bounding Box (AABB) Overlaps
For all pairs that satisfy the logical and state criteria, the
detector performs spatial checks using Axis-Aligned Bounding Boxes
(part.bounds). Every part's bounding box is dynamically
updated during engine updates to encompass its current position,
rotation, and vertices.
The detector checks for overlap along the X and Y axes using simple
min-max comparisons via
Bounds.overlaps(boundsA, boundsB):
- The maximum X of Box A must be greater than or equal to the minimum X of Box B, and vice versa.
- The maximum Y of Box A must be greater than or equal to the minimum Y of Box B, and vice versa.
If the bounding boxes do not overlap on both axes, the parts cannot possibly intersect, and the pair is rejected with minimal computational cost.
Passing Candidates to the Narrow Phase
When a pair of parts satisfies the hierarchy, sleep, bitmask, and
AABB criteria, Matter.Detector.collisions marks them as an
active collision candidate pair. The detector then forwards this
candidate pair to the narrow phase—typically handled by
Matter.SAT.collides (Separating Axis Theorem)—to determine
true vertex-level intersection, contact points, penetration depth, and
normal vectors.