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.

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:

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:

  1. (bodyA.collisionFilter.category & bodyB.collisionFilter.mask) !== 0
  2. (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.