Simulating Ground Friction in Matter.js
Simulating ground friction variation across materials like grass, mud, and ice in Matter.js requires configuring body friction properties and managing collision interactions dynamically. This guide explains how Matter.js calculates contact friction, how to assign appropriate surface properties to different terrain types, and how to use sensor zones and collision events to handle complex effects such as viscous drag in mud.
Understanding Contact Friction in Matter.js
Matter.js provides three primary properties to control body resistance:
friction: Kinetic friction during movement along a surface (range0to1).frictionStatic: Resistance required to initiate sliding (typically higher thanfriction).frictionAir: Drag or resistance applied to a body as it moves through space.
When two bodies make contact, Matter.js calculates the resulting friction using the minimum value of the two bodies by default:
\[\text{Effective Friction} = \min(\text{bodyA.friction}, \text{bodyB.friction})\]
Because of this rule, ensure that any moving object (such as a
vehicle or character) has its friction set sufficiently
high (e.g., 0.8 or 1.0). If the moving body
has a friction of 0.05, it will slide smoothly even over
high-friction grass because the engine resolves to the lower value.
Setting Up Terrain Segments
To create varied terrain, break your ground into distinct segments or blocks and assign tailored friction values to each surface type.
const { Bodies } = Matter;
// Ice: Extremely low kinetic and static friction
const iceGround = Bodies.rectangle(200, 500, 400, 40, {
isStatic: true,
friction: 0.002,
frictionStatic: 0.005,
render: { fillStyle: '#a5f2f3' }
});
// Grass: Moderate kinetic friction and standard grip
const grassGround = Bodies.rectangle(600, 500, 400, 40, {
isStatic: true,
friction: 0.15,
frictionStatic: 0.5,
render: { fillStyle: '#5dbb63' }
});
// Mud base: High kinetic friction to resist rolling and sliding
const mudGround = Bodies.rectangle(1000, 500, 400, 40, {
isStatic: true,
friction: 0.9,
frictionStatic: 1.0,
render: { fillStyle: '#654321' }
});Simulating Mud Viscosity with Sensor Zones
Surface friction alone is often insufficient for mud, as real mud
creates thick, viscous drag rather than mere surface roughness. You can
simulate depth and fluid resistance by layering a sensor body over the
mud surface to adjust the moving object's frictionAir.
1. Create a Mud Sensor
const mudZone = Bodies.rectangle(1000, 470, 400, 60, {
isStatic: true,
isSensor: true, // Allows objects to pass through without physical collision
label: 'mud_zone',
render: { fillStyle: 'rgba(101, 67, 33, 0.4)' }
});2. Detect Contact and Adjust Drag
Use collision events to detect when a body enters or exits the mud
zone, temporarily raising its frictionAir:
const DEFAULT_AIR_FRICTION = 0.01;
const MUD_AIR_FRICTION = 0.15;
Matter.Events.on(engine, 'collisionStart', (event) => {
event.pairs.forEach((pair) => {
const { bodyA, bodyB } = pair;
if (bodyA.label === 'mud_zone' && !bodyB.isStatic) {
bodyB.frictionAir = MUD_AIR_FRICTION;
} else if (bodyB.label === 'mud_zone' && !bodyA.isStatic) {
bodyA.frictionAir = MUD_AIR_FRICTION;
}
});
});
Matter.Events.on(engine, 'collisionEnd', (event) => {
event.pairs.forEach((pair) => {
const { bodyA, bodyB } = pair;
if (bodyA.label === 'mud_zone' && !bodyB.isStatic) {
bodyB.frictionAir = DEFAULT_AIR_FRICTION;
} else if (bodyB.label === 'mud_zone' && !bodyA.isStatic) {
bodyA.frictionAir = DEFAULT_AIR_FRICTION;
}
});
});Summary of Friction Settings
| Terrain | friction |
frictionStatic |
Implementation Method |
|---|---|---|---|
| Ice | 0.001 -
0.01 |
0.005 -
0.02 |
Solid static body |
| Grass | 0.1 - 0.2 |
0.4 - 0.6 |
Solid static body |
| Mud | 0.8 - 1.0 |
1.0 |
Solid static body + isSensor
zone modifying frictionAir |