Platformer Movement
Movement patterns for side-scrolling platformers and Mario-style games with gravity, jumping, and ground detection.
Basic Platformer Movement
Use Case: Side-scrolling platformers, Mario-style games
Game Definition
import { defineGame } from '@martini-kit/core';
const PLAYER_SPEED = 150;
const JUMP_VELOCITY = -400;
const GRAVITY = 800;
export const game = defineGame({
setup: ({ playerIds }) => ({
players: Object.fromEntries(
playerIds.map((id, index) => [
id,
{
x: 100 + index * 200,
y: 400,
vx: 0,
vy: 0,
onGround: false,
},
])
),
inputs: {} as Record<string, {
left: boolean;
right: boolean;
jump: boolean;
}>,
}),
actions: {
move: {
apply: (state, context, input: {
left: boolean;
right: boolean;
jump: boolean;
}) => {
const player = state.players[context.targetId];
if (!player) return;
// Horizontal movement
if (input.left) {
player.vx = -PLAYER_SPEED;
} else if (input.right) {
player.vx = PLAYER_SPEED;
} else {
player.vx = 0;
}
// Jump (only when on ground)
if (input.jump && player.onGround) {
player.vy = JUMP_VELOCITY;
player.onGround = false;
}
},
},
tick: {
apply: (state, context, input: { delta: number }) => {
const deltaSeconds = input.delta / 1000;
for (const player of Object.values(state.players)) {
// Apply gravity
if (!player.onGround) {
player.vy += GRAVITY * deltaSeconds;
}
// Update position
player.x += player.vx * deltaSeconds;
player.y += player.vy * deltaSeconds;
// Ground collision (simple)
const GROUND_Y = 550;
if (player.y >= GROUND_Y) {
player.y = GROUND_Y;
player.vy = 0;
player.onGround = true;
}
// Boundary clamping
player.x = Math.max(20, Math.min(780, player.x));
}
},
},
},
}); Phaser Scene with Physics
Using InputManager - Automatic input handling:
import { PhaserAdapter, InputManager, SpriteManager } from '@martini-kit/phaser';
create() {
this.adapter = new PhaserAdapter(runtime, this);
// Automatic WASD + Arrow + Space input
this.inputManager = new InputManager(this.adapter, this, {
type: 'platformer',
actionName: 'move',
jumpKey: 'SPACE',
});
// Create platform
const platform = this.add.rectangle(400, 570, 600, 20, 0x8b4513);
this.physics.add.existing(platform, true);
// Auto-sync player sprites
this.playerManager = new SpriteManager(this.adapter, this, {
collection: 'players',
createSprite: (player) => this.add.circle(player.x, player.y, 20, 0x00aaff),
updateSprite: (sprite, player) => {
sprite.x = player.x;
sprite.y = player.y;
},
});
}
update(time: number, delta: number) {
if (this.adapter.isHost()) {
this.runtime.submitAction('tick', { delta });
}
this.adapter.update(time, delta);
} Benefits:
- ✅ Automatic jump key handling
- ✅ Built-in ground detection support
- ✅ Less input boilerplate
Features:
- ✅ Gravity
- ✅ Jumping
- ✅ Ground detection
- ✅ Platform collision
See Also
- Top-Down Movement - Arena shooter and RPG movement
- Advanced Movement - Mouse/pointer and rotation
- Physics & Collision - Physics integration