Laser Tripwires with Raycasting in Matter.js
This article explains how to implement laser tripwires in Matter.js
by utilizing its built-in raycasting query methods. You will learn how
to set up the ray coordinates, evaluate line-of-sight intersections
against dynamic bodies using Matter.Query.ray, trigger
events when the beam is broken, and visually render the laser beam on an
HTML5 canvas.
Understanding Raycasting in Matter.js
Matter.js provides a built-in module called Matter.Query
for spatial queries. The Query.ray function tests a
directed line segment against a collection of physics bodies and returns
any intersections.
The syntax for Query.ray is:
Matter.Query.ray(bodies, startPoint, endPoint, [rayWidth])bodies: An array ofMatter.Bodyobjects to test against.startPoint: An object{ x, y }defining the origin of the ray.endPoint: An object{ x, y }defining the destination of the ray.rayWidth(optional): The thickness of the ray. Using a small value like1or2accounts for floating-point inaccuracies and simulates beam width.
The method returns an array of collision objects containing the intersected bodies and collision details.
Setting Up the Tripwire Logic
To detect when an entity trips the laser, perform the raycast inside
the engine's update loop using the beforeUpdate or
afterUpdate event. This ensures the query checks the
current positions of all active bodies on every frame.
const { Engine, Render, Runner, Bodies, Composite, Query, Events } = Matter;
// Initialize engine and world
const engine = Engine.create();
const world = engine.world;
// Create obstacles and moving bodies
const player = Bodies.rectangle(100, 200, 40, 40, { label: 'Player' });
const wall = Bodies.rectangle(400, 300, 800, 50, { isStatic: true });
Composite.add(world, [player, wall]);
// Define laser tripwire points
const laserStart = { x: 50, y: 200 };
const laserEnd = { x: 500, y: 200 };
const laserWidth = 2;
// Check for collisions every physics frame
Events.on(engine, 'afterUpdate', () => {
// Get all bodies currently in the world
const bodies = Composite.allBodies(world);
// Perform the raycast
const collisions = Query.ray(bodies, laserStart, laserEnd, laserWidth);
// Filter out static walls or the emitter body if necessary
const validHits = collisions.filter(collision => collision.body.label === 'Player');
if (validHits.length > 0) {
onTripwireTriggered(validHits);
}
});
function onTripwireTriggered(hits) {
console.log('Tripwire triggered by:', hits.map(h => h.body.label));
// Trigger alarms, open doors, or penalize the player here
}Rendering the Laser Beam
While Query.ray handles the physics logic, it does not
draw anything to the screen. To display the laser, draw directly onto
the rendering canvas using the Canvas 2D API.
Hook into the afterRender event of the
Matter.Render instance:
const render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
wireframes: false
}
});
Events.on(render, 'afterRender', () => {
const context = render.context;
// Check if the laser is currently obstructed
const bodies = Composite.allBodies(world);
const collisions = Query.ray(bodies, laserStart, laserEnd, laserWidth);
const isTripped = collisions.some(c => c.body.label === 'Player');
context.beginPath();
context.moveTo(laserStart.x, laserStart.y);
context.lineTo(laserEnd.x, laserEnd.y);
// Visual feedback: red when clear, yellow when tripped
context.strokeStyle = isTripped ? 'rgba(255, 255, 0, 0.9)' : 'rgba(255, 0, 0, 0.7)';
context.lineWidth = laserWidth;
context.shadowColor = isTripped ? 'yellow' : 'red';
context.shadowBlur = 10;
context.stroke();
// Reset shadow properties for other elements
context.shadowBlur = 0;
});Dynamic Beam Truncation
In realistic tripwire scenarios, a laser beam should stop at the surface of the first obstacle it hits rather than passing through it.
To achieve this:
- Iterate through the array returned by
Query.ray. - Determine which intersecting body is closest to
laserStart. - Read the collision contact point or project the distance to truncate
the
laserEndrendering coordinate to that hit point.