Create a Deformable Fishing Net in Matter.js
This article explains how to build a realistic, deformable fishing net in Matter.js using a mass-spring system. By arranging lightweight circular bodies into a two-dimensional grid and interconnecting them with distance constraints, you can simulate flexible, cloth-like physical behaviors that react dynamically to gravity, external forces, and collisions.
Core Concepts
A deformable net consists of two primary elements in Matter.js:
- Point Masses: Small, lightweight circular rigid
bodies (
Matter.Bodies.circle) representing the intersections or knots of the net. - Springs: Distance constraints
(
Matter.Constraint.create) connecting adjacent point masses to act as the threads of the net. Adjusting constraint stiffness controls how much the net stretches under load.
Step-by-Step Implementation
1. Setup the Matter.js Environment
Initialize the basic Matter.js modules: the engine, runner, renderer, and world composite.
const { Engine, Render, Runner, Bodies, Composite, Constraint, Mouse, MouseConstraint } = 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);2. Define Net Configuration
Set the dimensions and properties of the grid. Using a small radius for point masses prevents unwanted self-collisions while maintaining mass.
const cols = 15;
const rows = 10;
const spacing = 25;
const startX = 220;
const startY = 100;
const particleRadius = 3;
const stiffness = 0.8; // Elasticity of threads (0 = fully elastic, 1 = rigid)3. Generate Point Masses
Loop through rows and columns to generate the grid of bodies. Anchor
specific points (such as the top corners) by setting
isStatic: true to suspend the net in space.
const grid = [];
for (let y = 0; y < rows; y++) {
grid[y] = [];
for (let x = 0; x < cols; x++) {
// Pin top-left and top-right points to hang the net
const isPinned = (y === 0 && (x === 0 || x === cols - 1));
const particle = Bodies.circle(
startX + x * spacing,
startY + y * spacing,
particleRadius,
{
isStatic: isPinned,
frictionAir: 0.02,
collisionFilter: { group: -1 }, // Negative group prevents self-collision among knots
render: { fillStyle: '#ffffff' }
}
);
grid[y][x] = particle;
Composite.add(world, particle);
}
}4. Connect Masses with Constraints
Iterate through the generated grid and attach structural constraints horizontally and vertically. For increased structural integrity and resistance to shearing, diagonal cross-constraints can also be added.
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
// Horizontal connections
if (x < cols - 1) {
Composite.add(world, Constraint.create({
bodyA: grid[y][x],
bodyB: grid[y][x + 1],
stiffness: stiffness,
damping: 0.1,
render: { strokeStyle: '#555555', lineWidth: 1 }
}));
}
// Vertical connections
if (y < rows - 1) {
Composite.add(world, Constraint.create({
bodyA: grid[y][x],
bodyB: grid[y + 1][x],
stiffness: stiffness,
damping: 0.1,
render: { strokeStyle: '#555555', lineWidth: 1 }
}));
}
}
}5. Add Interactivity and Interaction Bodies
Add a mouse constraint to allow dragging parts of the net, as well as an external dynamic body to interact with it.
// Add a heavy object to fall into the net
const catchObject = Bodies.circle(400, 50, 20, {
density: 0.05,
render: { fillStyle: '#ff4757' }
});
Composite.add(world, catchObject);
// Enable mouse interaction
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;Tuning and Performance Considerations
- Engine Iterations: By default, Matter.js runs
constraints through limited iterations. If the net stretches unnaturally
or behaves like loose rubber, increase
engine.constraintIterationsandengine.positionIterationsto values between 4 and 8. - Collision Filtering: Setting
collisionFilter.group = -1on all net particles ensures they pass through one another cleanly without snagging internal springs, while still interacting normally with external bodies. - Tearing Mechanics: To simulate net breakage under
excessive load, iterate through constraints during
beforeUpdateevents, calculate the distance betweenbodyAandbodyB, and remove constraints that exceed a specified threshold length.