Matter.js collisionFilter Explained
The collisionFilter property in Matter.js is an object
attached to every physical body that dictates which other bodies it can
collide with. By configuring this property, developers can selectively
enable or disable physical interactions between specific entities, such
as allowing a player to pass through friendly characters while still
interacting with solid walls and enemies. This article covers the
structure of the collisionFilter object, how its three key
properties—category, mask, and
group—work, and how to implement collision filtering
effectively in your 2D physics simulations.
The Structure of collisionFilter
Every Matter.js body contains a default collisionFilter
object:
collisionFilter: {
category: 0x0001,
mask: 0xFFFFFFFF,
group: 0
}These three properties determine whether two bodies physically interact when they overlap.
1. The group Property
The group property is a signed integer that overrides
the category and mask rules when set to a
non-zero value.
- Zero (
0): The default behavior. When the group is0, Matter.js falls back to evaluating thecategoryandmaskbitmasks. - Positive Integer (e.g.,
1,2): If two bodies share the same positive group value, they will always collide, regardless of their categories or masks. - Negative Integer (e.g.,
-1,-2): If two bodies share the same negative group value, they will never collide, regardless of their categories or masks.
If two bodies have different group values, Matter.js ignores the
group and proceeds to check their category and
mask.
2. The category
Property
The category property is a 32-bit integer acting as a
bitmask that defines what "type" of entity the body is. Matter.js
supports up to 32 distinct categories, which should be represented as
powers of two in hexadecimal notation:
0x0001(1)0x0002(2)0x0004(4)0x0008(8)0x0010(16)- and so on, up to
0x80000000.
3. The mask Property
The mask property is a 32-bit integer that defines what
categories a body is allowed to collide with. You combine categories
using the bitwise OR (|) operator to create a mask:
const defaultCategory = 0x0001;
const playerCategory = 0x0002;
const enemyCategory = 0x0004;
// This body will only collide with default objects and enemies
const playerMask = defaultCategory | enemyCategory;The default mask value 0xFFFFFFFF means the body can
collide with every category.
Collision Logic Rule
For a collision to occur between Body A and Body B, both of the following bitwise conditions must be true:
(bodyA.collisionFilter.category & bodyB.collisionFilter.mask) !== 0(bodyB.collisionFilter.category & bodyA.collisionFilter.mask) !== 0
If either evaluation results in 0, the collision is
ignored and the bodies pass through each other.
Practical Implementation
Below is an example configuring a player, an enemy, and a projectile that only hits enemies:
const PLAYER = 0x0001;
const ENEMY = 0x0002;
const BULLET = 0x0004;
// Player collides with enemies, but not its own bullets
const player = Bodies.rectangle(100, 100, 50, 50, {
collisionFilter: {
category: PLAYER,
mask: ENEMY
}
});
// Enemy collides with both players and bullets
const enemy = Bodies.rectangle(200, 100, 50, 50, {
collisionFilter: {
category: ENEMY,
mask: PLAYER | BULLET
}
});
// Bullet only collides with enemies
const bullet = Bodies.circle(120, 100, 5, {
collisionFilter: {
category: BULLET,
mask: ENEMY
}
});Using collisionFilter optimizes performance by filtering
out unwanted interactions at the collision detection phase, preventing
unnecessary collision resolution calculations.