Matter.js Detector Collision Filtering Explained
In Matter.js, performance is optimized during the broad-phase
collision detection stage by skipping costly geometric calculations
between bodies that are configured not to interact. The
Matter.Detector module achieves this through the internal
canCollide(filterA, filterB) method, which evaluates each
rigid body's collisionFilter object. This article breaks
down the exact criteria—namely collision groups, category bitfields, and
mask bitfields—that Matter.Detector uses to skip collision
checks between incompatible bodies.
The Priority Rule: Collision Groups
Before evaluating categories or masks, Matter.Detector
checks the group property (filter.group).
Collision groups override standard category and mask behavior:
- Same Negative Group: If both bodies share the same
non-zero negative integer (e.g.,
filterA.group === -1andfilterB.group === -1), the collision check is skipped immediately. - Same Positive Group: If both bodies share the same
non-zero positive integer (e.g.,
filterA.group === 1andfilterB.group === 1), a collision is guaranteed to be tested, bypassing category/mask checks entirely. - Different Groups or Zero: If the groups differ or
are set to
0(the default value), the detector moves on to evaluate the category and mask rules.
The Category and Mask Bitwise Criteria
When group rules do not apply, Matter.Detector
determines collision compatibility using bitwise operations between each
body's category and mask properties.
By default, every body in Matter.js has:
category:0x0001(a bitfield identifying the body's type)mask:0xFFFFFFFF(a bitmask indicating all categories it can collide with)
For two bodies, Body A and Body B, to be eligible for collision
detection, the following boolean condition must evaluate to
true:
(filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0Why Collision Checks Are Skipped
Matter.Detector will immediately discard the pair and
skip narrow-phase collision calculations if either of the following
conditions is met:
- Body A does not listen to Body B: The bitwise AND
between Body A's
maskand Body B'scategoryresults in0((filterA.mask & filterB.category) === 0). - Body B does not listen to Body A: The bitwise AND
between Body B's
maskand Body A'scategoryresults in0((filterB.mask & filterA.category) === 0).
Because the check requires two-way consent via the logical AND
(&&), compatibility must be mutual. If even one
body's mask excludes the other body's category bit,
Matter.Detector eliminates the pair from the collision
pipeline.