Getting Started with Matter.js: A Guide to Interactive Physics Simulations
Core Concepts
Matter.js is a 2D JavaScript physics engine for simulating realistic physical interactions in web applications. Key components include:
| Component | Description |
|---|---|
| Engine | Manages the physics world, calculating motion and interactions. |
| Renderer | Visualizes physics objects on a canvas. |
| Composite | Container for grouping multiple bodies and constraints. |
| Body | Physical entity with properties like shape, mass, and velocity (e.g., rectangles, circles). |
| Constraint | Restricts relative motion between bodies (e.g., fixed distance, rotation limits). |
| Runner | Controls the engine's update loop for continuous simulation. |
Installation
CDN
Include via CDN:
<script src="https://cdn.bootcdn.net/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
NPM
Install with npm:
npm install matter-js
Basic Simulation Setup
Create a simple scene with falling boxes and a static ground.
<div id="simulation-container"></div>
<script src="https://cdn.bootcdn.net/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
<script>
const { Engine, Render, Bodies, Composite, Runner } = Matter;
// Initialize physics engine
const physicsEngine = Engine.create();
// Set up renderer
const viewRenderer = Render.create({
element: document.getElementById('simulation-container'),
engine: physicsEngine,
options: { width: 800, height: 600 }
});
// Create dynamic bodies
const firstBox = Bodies.rectangle(400, 200, 80, 80);
const secondBox = Bodies.rectangle(450, 50, 80, 80);
// Create static ground
const floor = Bodies.rectangle(400, 610, 810, 60, { isStatic: true });
// Add bodies to the world
Composite.add(physicsEngine.world, [firstBox, secondBox, floor]);
// Start rendering and simulation
Render.run(viewRenderer);
const simulationRunner = Runner.create();
Runner.run(simulationRunner, physicsEngine);
</script>
Renderer Configuration
Customize the renderer with options:
const viewRenderer = Render.create({
element: document.getElementById('container'),
engine: physicsEngine,
options: {
width: 400,
height: 400,
wireframes: false, // Disable wireframe mode
background: '#f0f0f0'
}
});
Creating Shapes
Basic Shapes
Use Bodies methods to create primitives:
-
Rectangle:
Bodies.rectangle(x, y, width, height, options)const rectangle = Bodies.rectangle(100, 100, 80, 60, { render: { fillStyle: 'orange' } }); -
Circle:
Bodies.circle(x, y, radius, options)const circle = Bodies.circle(200, 150, 40, { render: { fillStyle: 'blue' } }); -
Trapezoid:
Bodies.trapezoid(x, y, width, height, slope, options)const trapezoid = Bodies.trapezoid(300, 200, 80, 60, 0.5); -
Polygon:
Bodies.polygon(x, y, sides, radius, options)const hexagon = Bodies.polygon(400, 250, 6, 30);
Custom Polygon
Define vertices with Bodies.fromVertices:
const customShape = Bodies.fromVertices(500, 300, [
{ x: 0, y: 0 }, { x: 50, y: 0 }, { x: 50, y: 50 }, { x: 25, y: 75 }, { x: 0, y: 50 }
]);
Body Properties
Configure physical and visual attributes:
-
Bounciness:
restitution(0–1, >1 for game mechanics)Bodies.rectangle(100, 50, 60, 60, { restitution: 0.8 }); -
Air Resistance:
frictionAir(0–1, higher = more drag)Bodies.circle(200, 50, 30, { frictionAir: 0.05 }); -
Mass:
mass(affects inertia)Bodies.rectangle(300, 50, 60, 60, { mass: 5 }); -
Rotation:
angle(radians)Bodies.rectangle(400, 50, 60, 60, { angle: Math.PI / 4 }); // 45 degrees -
Static State:
isStatic: true(immovable object)Bodies.rectangle(500, 350, 800, 40, { isStatic: true });
Composite Stacks
Group bodies with Composites.stack:
const blockStack = Composites.stack(20, 20, 6, 3, 10, 20, (x, y) => {
return Bodies.rectangle(x, y, 30, 30, { restitution: 0.5 });
});
Composite.add(physicsEngine.world, blockStack);
Constraints
Link bodies with joints:
const plank = Bodies.rectangle(200, 300, 200, 20);
const fulcrum = Bodies.circle(200, 320, 10, { isStatic: true });
const seesawJoint = Constraint.create({
bodyA: plank,
bodyB: fulcrum,
pointA: { x: 0, y: 10 },
stiffness: 0.8
});
Composite.add(physicsEngine.world, [plank, fulcrum, seesawJoint]);
Mouse Interaction
Enable drag-and-drop with mouse constraints:
const mouse = Mouse.create(viewRenderer.canvas);
const dragControl = MouseConstraint.create(physicsEngine, {
mouse: mouse,
constraint: { stiffness: 0.2, render: { visible: false } }
});
Composite.add(physicsEngine.world, dragControl);
Event Handling
Listen for collisions:
Events.on(physicsEngine, 'collisionStart', (event) => {
event.pairs.forEach(pair => {
console.log('Collision detected:', pair.bodyA, pair.bodyB);
});
});
Listen for mouse events:
Events.on(dragControl, 'startdrag', (event) => {
console.log('Dragging started:', event.body);
});