How to Create Sensor Bodies in Matter.js

In Matter.js, a sensor body is a physics body that detects collisions and triggers events without producing physical forces, friction, or bounces against other objects. This article explains how to configure a body as a sensor using the isSensor flag, listen for overlap events using the engine's event system, and apply this pattern for gameplay triggers such as checkpoints, pickups, and zone detection.

Setting the isSensor Property

To convert any standard rigid body into a sensor, set its isSensor property to true. This property can be defined directly during the body's initialization or toggled dynamically on an existing body.

On Initialization

Pass isSensor: true within the options object when creating a body:

const { Bodies } = Matter;

// Create a rectangular sensor zone
const triggerZone = Bodies.rectangle(400, 300, 200, 100, {
  isSensor: true,
  isStatic: true, // Typically static if used as an area trigger
  render: {
    fillStyle: 'rgba(0, 255, 0, 0.3)',
    strokeStyle: 'green',
    lineWidth: 1
  }
});

Dynamically Updating an Existing Body

To turn an existing solid body into a sensor or vice versa at runtime, use the Body.set method:

const { Body } = Matter;

// Enable sensor mode
Body.set(myBody, 'isSensor', true);

// Disable sensor mode (reverts to solid physical interactions)
Body.set(myBody, 'isSensor', false);

Detecting Sensor Collisions

Because sensor bodies do not physically interact with other bodies, you must handle interactions through the Matter.Events module by listening to collision lifecycle events: collisionStart, collisionActive, and collisionEnd.

Listening for Collisions

The collisionStart event fires the first frame two bodies overlap:

const { Events } = Matter;

Events.on(engine, 'collisionStart', (event) => {
  const pairs = event.pairs;

  for (let i = 0; i < pairs.length; i++) {
    const { bodyA, bodyB } = pairs[i];

    // Check if one of the bodies is our trigger zone
    if (bodyA === triggerZone || bodyB === triggerZone) {
      const otherBody = bodyA === triggerZone ? bodyB : bodyA;
      
      console.log('An object entered the sensor zone:', otherBody);
      // Trigger game logic, such as awarding points or opening a door
    }
  }
});

Detecting Exit Events

To detect when an object leaves the sensor's boundary, listen to the collisionEnd event using the exact same pair-checking logic:

Events.on(engine, 'collisionEnd', (event) => {
  const pairs = event.pairs;

  for (let i = 0; i < pairs.length; i++) {
    const { bodyA, bodyB } = pairs[i];

    if (bodyA === triggerZone || bodyB === triggerZone) {
      const otherBody = bodyA === triggerZone ? bodyB : bodyA;
      
      console.log('An object exited the sensor zone:', otherBody);
    }
  }
});

Controlling Which Bodies Trigger the Sensor

Sensors obey the same collisionFilter rules as standard rigid bodies. If a sensor should only detect specific bodies (such as the player character and not background projectiles), configure the category and mask bitmasks on the sensor's collisionFilter:

const PLAYER_CATEGORY = 0x0001;
const ENEMY_CATEGORY  = 0x0002;

const playerDetector = Bodies.circle(400, 200, 50, {
  isSensor: true,
  isStatic: true,
  collisionFilter: {
    category: 0x0004,
    mask: PLAYER_CATEGORY // Only reports collisions with bodies belonging to PLAYER_CATEGORY
  }
});