Skip to main content

2D Physics (Matter.js)

GameByte wraps Matter.js for easy 2D physics.

World Setup

import { Physics } from '@gamebyte/framework';

Physics.create2DWorld({
gravity: { x: 0, y: 1 }, // Earth-like gravity
enableSleeping: true, // Bodies can sleep when still
timestep: 1/60 // Fixed timestep
});
🎮2D Physics Demo
Loading demo...
Theme Support

This demo automatically adapts to your selected theme. Try toggling the theme using the 🌙/☀️ button in the navigation bar!

Creating Bodies

Dynamic Body

const player = Physics.createBody({
x: 100,
y: 100,
width: 32,
height: 48,
options: {
label: 'player',
friction: 0.1,
restitution: 0, // No bounce
frictionAir: 0.01, // Air resistance
mass: 1
}
});

Static Body (Platforms)

const platform = Physics.createStaticBody({
x: 400,
y: 500,
width: 200,
height: 20,
options: {
label: 'platform'
}
});

Circle Body

const ball = Physics.createCircleBody({
x: 200,
y: 100,
radius: 25,
options: {
label: 'ball',
restitution: 0.8 // Bouncy
}
});

Applying Forces

// Set velocity directly
Physics.setVelocity(player, { x: 5, y: 0 });
Physics.setVelocityX(player, 5);
Physics.setVelocityY(player, -10); // Jump

// Apply force (acceleration)
Physics.applyForce(player, { x: 0.01, y: 0 });

// Apply force at point
Physics.applyForceAtPosition(player, { x: 0, y: -0.1 }, { x: 100, y: 100 });

Collision Detection

// Collision between labels
Physics.onCollision('player', 'enemy', (playerBody, enemyBody) => {
console.log('Player hit enemy!');
takeDamage();
});

// Collision with any body
Physics.onCollisionStart('player', (playerBody, otherBody) => {
if (otherBody.label === 'ground') {
canJump = true;
}
});

Physics.onCollisionEnd('player', (playerBody, otherBody) => {
if (otherBody.label === 'ground') {
canJump = false;
}
});

Platformer Controller

class PlatformerController {
private body: Matter.Body;
private speed = 5;
private jumpForce = -12;
private isGrounded = false;

constructor() {
this.body = Physics.createBody({
x: 100, y: 100,
width: 32, height: 48,
options: { label: 'player', friction: 0.1 }
});

this.setupCollisions();
}

private setupCollisions(): void {
Physics.onCollisionStart('player', (_, other) => {
if (other.label === 'platform') {
this.isGrounded = true;
}
});

Physics.onCollisionEnd('player', (_, other) => {
if (other.label === 'platform') {
this.isGrounded = false;
}
});
}

update(input: { left: boolean, right: boolean, jump: boolean }): void {
// Horizontal movement
let vx = 0;
if (input.left) vx = -this.speed;
if (input.right) vx = this.speed;
Physics.setVelocityX(this.body, vx);

// Jump
if (input.jump && this.isGrounded) {
Physics.setVelocityY(this.body, this.jumpForce);
this.isGrounded = false;
}
}

getPosition(): { x: number, y: number } {
return this.body.position;
}
}

Sensors (Triggers)

// Sensor doesn't collide but detects overlap
const trigger = Physics.createBody({
x: 300, y: 300,
width: 100, height: 100,
options: {
label: 'coin-area',
isSensor: true // No physical collision
}
});

Physics.onCollision('player', 'coin-area', () => {
collectCoin();
});

Constraints (Joints)

// Distance constraint (rope/spring)
const rope = Physics.createConstraint(bodyA, bodyB, {
length: 100,
stiffness: 0.1
});

// Pin constraint (hinge)
const hinge = Physics.createConstraint(door, null, {
pointA: { x: -50, y: 0 }, // Relative to body
pointB: { x: 100, y: 200 } // World position
});

Syncing with Sprites

class PhysicsSprite {
public sprite: PIXI.Sprite;
public body: Matter.Body;

constructor(texture: PIXI.Texture, x: number, y: number) {
this.sprite = new PIXI.Sprite(texture);
this.sprite.anchor.set(0.5);

this.body = Physics.createBody({
x, y,
width: texture.width,
height: texture.height
});
}

update(): void {
// Sync sprite with physics body
this.sprite.position.set(this.body.position.x, this.body.position.y);
this.sprite.rotation = this.body.angle;
}
}

Debug Rendering

// Enable physics debug view
game.setConfig({
debug: {
showPhysics: true
}
});

// Or manually
Physics.setDebug(true);