| name | dev-phaser-physics-matter |
| description | Matter.js physics: realistic bodies, constraints, and simulation |
Phaser Matter Physics
"Realistic physics simulation for puzzles and complex interactions."
Before/After: Manual Physics vs Matter.js Constraints
❌ Before: Manual Physics Simulation
interface Body {
x: number; y: number;
vx: number; vy: number;
mass: number;
angle: number;
angularVelocity: number;
}
const bodies: Body[] = [];
function updatePhysics(dt: number) {
for (const body of bodies) {
body.vy += 9.8 * dt;
}
for (let i = 0; i < bodies.length; i++) {
for (let j = i + 1; j < bodies.length; j++) {
if (checkCollision(bodies[i], bodies[j])) {
resolveCollision(bodies[i], bodies[j]);
}
}
}
for (const body of bodies) {
body.x += body.vx * dt;
body.y += body.vy * dt;
body.angle += body.angularVelocity * dt;
}
}
✅ After: Phaser Matter Physics
export class GameScene extends Phaser.Scene {
create() {
this.physics.world.setBounds(0, 0, 800, 600);
const box1 = this.matter.add.image(300, 200, 'box');
box1.setRectangle(40, 40);
box1.setStatic(true);
const box2 = this.matter.add.image(300, 300, 'box');
box2.setRectangle(40, 40);
this.matter.add.constraint(box1, box2, 100, 0.9, {
render: { visible: true }
});
springBox = ...(, , );
...(
{ : , : },
springBox,
,
,
{ : }
);
}
}
When to Use This Skill
Use when:
- Building physics puzzle games
- Need realistic collision and physics
- Working with complex body shapes
- Using constraints and joints
- Simulating realistic object interactions
Quick Start
physics: {
default: 'matter',
matter: {
gravity: { y: 1 },
debug: false
}
}
const box = this.matter.add.image(400, 300, 'box');
box.setRectangle();
Decision Framework
| Need | Use |
|---|
| Physics puzzles | Matter physics |
| Realistic stacking | Matter with friction |
| Ropes/chains | Constraints |
| Complex shapes | Custom body vertices |
| Simple platformer | Arcade instead |
Progressive Guide
Level 1: Basic Matter Bodies
export class GameScene extends Phaser.Scene {
create() {
const box = this.matter.add.image(400, 100, "box");
box.setRectangle();
box.setBounce(0.5);
box.setFriction(0.1);
const ball = this.matter.add.image(400, 200, "ball");
ball.setCircle();
ball.setBounce(0.8);
const ground = this.matter.add.image(400, 550, "ground");
ground.setStatic(true);
ground.setRectangle(800, 50);
}
}
Level 2: Custom Body Shapes
create() {
const triangle = this.matter.add.image(400, 100, 'triangle');
triangle.setPolygon(0, 0, [
{ x: 0, y: -30 },
{ x: 30, y: 30 },
{ x: -30, y: 30 }
]);
const rock = this.matter.add.image(400, 200, 'rock');
rock.setPolygon(0, 0, [
{ x: -25, y: -20 },
{ x: 20, y: -25 },
{ x: 30, y: 10 },
{ x: 10, y: 30 },
{ x: -20, y: }
]);
compound = ...(, , );
compound.(, );
compound.();
compound.();
}
Level 3: Constraints and Joints
create() {
const box1 = this.matter.add.image(300, 200, 'box');
box1.setRectangle(40, 40);
box1.setStatic(true);
const box2 = this.matter.add.image(300, 300, 'box');
box2.setRectangle(40, 40);
this.matter.add.constraint(box1, box2, 100, 0.9, {
render: { visible: true }
});
const door = this.matter.add.image(400, 300, 'door');
door.setRectangle(10, 100);
this.matter.add.constraint(door, { x: , : }, , , {
: { : , : - },
: { : , : }
});
springBox = ...(, , );
springBox.(, );
...(
{ : , : },
springBox,
,
,
{ : }
);
}
Level 4: Physics Events and Collision
create() {
this.matter.world.on('collisionstart', (event: any) => {
event.pairs.forEach((pair: any) => {
const bodyA = pair.bodyA;
const bodyB = pair.bodyB;
if (bodyA.label === 'player' && bodyB.label === 'coin') {
this.collectCoin(bodyB.gameObject);
}
});
});
const player = this.matter.add.image(400, 300, 'player');
player.setRectangle();
(player.body as MatterJS.Body).label = 'player';
const coin = this.matter.add.image(400, 400, );
coin.();
(coin. .). = ;
}
Level 5: Advanced Matter Physics
export class PhysicsScene extends Phaser.Scene {
private bridgeParts: Phaser.Physics.Matter.Image[] = [];
create() {
this.createBridge();
this.createRope();
this.createPhysicsStack();
}
createBridge() {
const startX = 200;
const startY = 200;
const plankCount = 8;
const plankWidth = 60;
const gap = 5;
let previousPlank: Phaser.Physics.Matter.Image | null = null;
for (let i = 0; i < plankCount; i++) {
const x = startX + i * (plankWidth + gap);
const y = startY;
const plank = this.matter.add.image(x, y, "plank");
plank.setRectangle(plankWidth, );
plank.();
plank.();
..(plank);
(i === || i === plankCount - ) {
plank.();
}
(previousPlank) {
...(
previousPlank,
plank,
plankWidth + gap,
,
{
: { : plankWidth / , : },
: { : -plankWidth / , : },
},
);
}
previousPlank = plank;
}
}
() {
links = ;
linkLength = ;
startX = ;
startY = ;
: ... | = ;
( i = ; i < links; i++) {
link = ...(startX, startY + i * linkLength, );
link.();
link.();
(i === ) {
link.();
}
(prevLink) {
...(prevLink, link, linkLength, );
}
prevLink = link;
}
}
() {
stackSize = ;
boxSize = ;
startX = ;
startY = ;
( row = ; row < stackSize; row++) {
( col = ; col < stackSize - row; col++) {
x = startX + col * boxSize + row * (boxSize / );
y = startY - row * boxSize;
box = ...(x, y, );
box.(boxSize, boxSize);
box.();
box.();
box.();
}
}
}
}
Anti-Patterns
❌ DON'T:
- Use Matter for simple platformers - Arcade is better
- Set high density on all objects - causes instability
- Ignore sleep settings - kills performance
- Create complex constraints without tuning
- Mix body coordinates systems arbitrarily
- Forget to set static on anchored objects
✅ DO:
- Use Matter for puzzles, stacking, complex interactions
- Adjust density based on object type
- Enable sleep for inactive bodies
- Test constraint values iteratively
- Keep coordinates consistent
- Set static bodies for anchors/ground
Code Patterns
Body Configuration
const box = this.matter.add.image(400, 300, "box");
box.setRectangle(width, height);
box.setCircle(radius);
box.setPolygon(x, y, vertices);
box.setTrapezoid(width, height, slope);
box.setBounce(0.5);
box.setFriction(0.1);
box.setFrictionStatic(0.5);
box.setDensity(0.001);
box.setAngle(Math.PI / 4);
box.setStatic(true);
box.setSensor(true);
Constraint Types
this.matter.add.constraint(bodyA, bodyB, length, stiffness);
this.matter.add.spring(bodyA, bodyB, length, stiffness, config);
this.matter.add.constraint(body, { x, y }, length, stiffness);
this.matter.add.constraint(bodyA, bodyB, length, stiffness, {
pointA: { x: offsetX, y: offsetY },
pointB: { x: offsetX, y: offsetY },
});
Matter vs Arcade Comparison
| Feature | Arcade | Matter |
|---|
| Performance | Faster | Slower |
| Complexity | Simple | Complex |
| Collision | AABB/OBB | SAT/Polygon |
| Constraints | Basic | Advanced |
| Best For | Platformers, top-down | Puzzles, realistic physics |
| Body Types | Dynamic/Static | Dynamic/Static/Sensor |
Checklist
Reference