Simulating a Slingshot with Matter.js Elastic Bands
This article covers how to build an interactive slingshot mechanic using Matter.js, a 2D physics engine for the web. You will learn how to configure the physics engine, create an elastic band using spring constraints, attach a projectile, handle mouse dragging interactions, and programmatically release the projectile to launch it through 2D space.
Core Mechanics Overview
A functional slingshot simulation in Matter.js requires four primary components:
- Anchor Point: A static reference point where the elastic band is anchored.
- Projectile: A dynamic rigid body that the player pulls and launches.
- Elastic Constraint: A Matter.js
Constraintacting as the elastic band, defined with specific stiffness and damping values. - Release Logic: An event listener that detects when the user releases the projectile and detaches the constraint at the right moment.
Step 1: Setting Up the Physics Engine and World
Initialize the standard Matter.js modules: Engine,
Render, Runner, Bodies,
Composite, Constraint, Mouse, and
MouseConstraint.
const { Engine, Render, Runner, Bodies, Composite, Constraint, Mouse, MouseConstraint, Events } = Matter;
const engine = Engine.create();
const world = engine.world;
const render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
wireframes: false
}
});
Render.run(render);
Runner.run(Runner.create(), engine);Step 2: Creating the Projectile and Elastic Constraint
Create a dynamic circle body for the projectile. Place the anchor
point at the slingshot's rest position, then connect the projectile to
this anchor using a Constraint.
const anchor = { x: 200, y: 400 };
// Create the projectile
const projectile = Bodies.circle(anchor.x, anchor.y, 20, {
density: 0.004,
restitution: 0.8,
render: { fillStyle: '#e74c3c' }
});
// Create the elastic band constraint
const elastic = Constraint.create({
pointA: anchor,
bodyB: projectile,
stiffness: 0.05,
damping: 0.01,
render: {
strokeStyle: '#e67e22',
lineWidth: 5
}
});
Composite.add(world, [projectile, elastic]);- Stiffness: Controls the snap of the band (values
between
0.01and0.2work best for stretchable rubber bands). - Damping: Controls energy loss to prevent infinite oscillation.
Step 3: Enabling Mouse Dragging
Add a MouseConstraint so players can click and pull the
projectile backward.
const mouse = Mouse.create(render.canvas);
const mouseConstraint = MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: { visible: false }
}
});
Composite.add(world, mouseConstraint);
render.mouse = mouse;Step 4: Coding the Launch Release Logic
A common slingshot mechanic releases the projectile when the user
lets go of the mouse button while dragging. Using Matter.js events,
check when dragging ends (enddrag), determine if the
released body is the projectile, and detach the elastic constraint once
it springs past or reaches the anchor position.
let isFired = false;
Events.on(mouseConstraint, 'enddrag', (event) => {
if (event.body === projectile) {
isFired = true;
}
});
Events.on(engine, 'afterUpdate', () => {
if (isFired) {
// Check if the projectile has moved forward past the anchor point
const distanceX = projectile.position.x - anchor.x;
// Release the projectile when it crosses forward or snaps back close to the anchor
if (distanceX > 0 || projectile.speed > 20) {
Composite.remove(world, elastic);
isFired = false;
}
}
});Step 5: Reloading the Slingshot
To allow successive shots, spawn a new projectile and reconnect the constraint after the previous projectile moves out of view or comes to rest:
function reloadSlingshot() {
const newProjectile = Bodies.circle(anchor.x, anchor.y, 20, {
density: 0.004,
restitution: 0.8,
render: { fillStyle: '#e74c3c' }
});
elastic.bodyB = newProjectile;
Composite.add(world, [newProjectile, elastic]);
}This completes the slingshot mechanic. Adjusting the
stiffness and density parameters will allow
you to calibrate shot velocity, band tension, and projectile weight to
fit your game design.