Moving Platforms in Matter.js Without Slipping
Moving platforms in Matter.js often fail to carry dynamic bodies because standard static bodies and direct position updates do not transfer velocity to objects resting on top of them. To create moving platforms that carry a player without slipping, you must update the platform using continuous kinematic velocities rather than hard position shifts, configure appropriate friction values, or manually translate the player by the platform’s displacement during the physics step.
Why Slipping Occurs
By default, setting an object to isStatic: true and
changing its position via Body.setPosition() teleports the
body. Because its calculated velocity remains zero, the physics engine
generates no frictional force against any body standing on top of it.
Even if friction is set to maximum, the resting player stays in place in
world space while the platform slides underneath.
Step 1: Use
Kinematic Motion with Body.setVelocity
To ensure the engine natively calculates friction and momentum, you must explicitly set the platform's velocity on every frame instead of directly modifying coordinates:
const platform = Matter.Bodies.rectangle(x, y, width, height, {
isStatic: true // or isKinematic: true in newer versions
});
// In your game loop (before Matter.Engine.update):
const speedX = 2; // Moving right
Matter.Body.setVelocity(platform, { x: speedX, y: 0 });
Matter.Body.setPosition(platform, {
x: platform.position.x + speedX,
y: platform.position.y
});Step 2: Configure Contact Friction
Friction must be elevated on both the platform and the player to prevent inertia from separating them during acceleration:
// Platform setup
platform.friction = 1;
platform.frictionStatic = 10;
// Player setup
player.friction = 1;
player.frictionStatic = 10;While high friction works well for linear paths with constant speeds, platforms that accelerate or change directions quickly may still cause the player to slide.
Step 3: Implement Relative Position Synchronization
The most reliable way to prevent slipping entirely is to detect when the player is grounded on a platform and directly add the platform's displacement to the player before the engine updates.
- Detect Ground Contact: Use Matter.js collision events to verify if the player's feet are touching the platform.
let currentPlatform = null;
Matter.Events.on(engine, 'collisionActive', (event) => {
event.pairs.forEach((pair) => {
if (
(pair.bodyA === player && pair.bodyB === platform) ||
(pair.bodyB === player && pair.bodyA === platform)
) {
// Ensure collision normal indicates the player is on top
if (player.position.y < platform.position.y) {
currentPlatform = platform;
}
}
});
});
Matter.Events.on(engine, 'collisionEnd', (event) => {
event.pairs.forEach((pair) => {
if (pair.bodyA === platform || pair.bodyB === platform) {
currentPlatform = null;
}
});
});- Apply Platform Displacement in
beforeUpdate: Translate the player body by the platform's velocity vector during thebeforeUpdateevent.
Matter.Events.on(engine, 'beforeUpdate', () => {
if (currentPlatform) {
Matter.Body.translate(player, {
x: currentPlatform.velocity.x,
y: currentPlatform.velocity.y
});
}
});Using this approach eliminates relative slip regardless of the platform's speed, rotation, or direction changes.