How to Prevent Sliding on Slopes in Matter.js
Preventing a character from unintentionally sliding down inclined surfaces is a common challenge in 2D physics engines like Matter.js. By default, gravity decomposes along the angle of a slope, creating a lateral force that overcomes default friction values. This article covers practical techniques to eliminate unwanted slope sliding, including dynamic friction switching, counteracting gravitational forces, and manually clamping velocity during idle states.
1. Dynamic Friction Adjustments
A standard character body usually requires low friction
(friction: 0 or 0.001) to prevent getting
stuck on vertical walls during movement. However, low friction causes
immediate sliding on slopes. The simplest fix is to dynamically toggle
friction properties depending on whether the player is actively moving
or stationary.
When player input is zero and the character is grounded:
// When stationary on ground
Matter.Body.set(playerBody, {
friction: 1,
frictionStatic: 10
});
// When moving via player input
Matter.Body.set(playerBody, {
friction: 0.001,
frictionStatic: 0
});Make sure the slope surface also has adequate friction (e.g.,
friction: 1, frictionStatic: 2) so the two
surfaces create enough resistance to counter the slope component of
gravity.
2. Zeroing Velocity on Idle
Friction-based solutions can sometimes cause jitter on steep slopes. A more reliable alternative is to cancel velocity directly when the character is on the ground and receiving no directional input.
Listen to the engine's beforeUpdate event:
Matter.Events.on(engine, 'beforeUpdate', () => {
if (isGrounded && !isMovingInput) {
// Halt sliding by locking horizontal and downward drift
if (Math.abs(playerBody.velocity.x) < 0.1) {
Matter.Body.setVelocity(playerBody, {
x: 0,
y: Math.min(0, playerBody.velocity.y)
});
}
}
});To make this work effectively, you must track isGrounded
using collision events (collisionStart,
collisionActive, collisionEnd) via bottom
sensors or raycasting.
3. Cancelling Gravity on the Character
If you control character movement purely via kinematic methods (setting velocity manually), you can negate the effect of the world's gravity on the player body specifically when grounded.
Matter.Events.on(engine, 'beforeUpdate', () => {
if (isGrounded && !isMovingInput) {
const gravity = engine.gravity;
// Apply an equal and opposite force to global gravity
Matter.Body.applyForce(playerBody, playerBody.position, {
x: -gravity.x * gravity.scale * playerBody.mass,
y: -gravity.y * gravity.scale * playerBody.mass
});
// Dampen residual movement
Matter.Body.setVelocity(playerBody, { x: 0, y: 0 });
}
});4. Chamfered or Capsule Colliders
Square and rectangular bodies tend to snag or rotate on slope edges.
Use a capsule (a rectangle with rounded ends using
Matter.Bodies.rectangle with
chamfer: { radius: ... }) to ensure uniform contact
geometry. Always set inertia: Infinity on the character
body to prevent the physics engine from rotating the player as it
interacts with inclined surfaces.