Detect Collisions Without Physics in Matter.js

This article explains how to create a "ghost" or sensor body in Matter.js that detects overlaps and triggers events without causing any physical displacement, bouncing, or solid collision response. By setting the isSensor property to true, you can easily implement triggers, pickup zones, checkpoints, and vision cones in your 2D physics simulations.

The isSensor Property

Matter.js provides a built-in property for bodies called isSensor. When a body is defined as a sensor, the physics engine still registers and fires collision events for it, but completely skips the collision resolution step. This means other rigid bodies will pass straight through it instead of bouncing off or being blocked.

Creating a Ghost Body

You can enable this behavior by passing isSensor: true in the body's options object during creation:

const { Bodies, World } = Matter;

// Create a static ghost/sensor body (e.g., a trigger zone or checkpoint)
const triggerZone = Bodies.rectangle(400, 300, 200, 100, {
    isSensor: true,
    isStatic: true,
    render: {
        fillStyle: 'rgba(0, 255, 0, 0.3)' // Semi-transparent visual
    }
});

World.add(engine.world, triggerZone);

You can also make dynamic (moving) bodies sensors using the same property:

const ghostBullet = Bodies.circle(100, 100, 10, {
    isSensor: true
});

Changing an Existing Body to a Sensor

If you have an existing body, you can toggle its sensor state dynamically at any point by modifying the property directly:

myBody.isSensor = true;

Detecting Collisions with the Sensor

To detect when an object enters, remains within, or leaves the ghost body, listen to the collision events provided by Matter.Events:

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 colliding bodies is our trigger zone
        if (bodyA === triggerZone || bodyB === triggerZone) {
            const otherBody = bodyA === triggerZone ? bodyB : bodyA;
            console.log('Object entered the trigger zone:', otherBody);
        }
    }
});

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('Object left the trigger zone:', otherBody);
        }
    }
});

Difference Between isSensor and collisionFilter

Matter.js also allows you to control collisions using collisionFilter masks and categories. However, setting collision filters to avoid collisions will prevent the engine from generating collision events entirely. Use isSensor: true when you still need to capture overlap events via code while bypassing physical forces.