Co-op movement
For co-op, players are on the same side, so cheating barely matters. Keep movement client-owned for zero-latency feel, and add one small validator so a bug (or a bad actor) can’t teleport across the map.
Schema
export const schema = defineSchema({
players: map(entity({ x: number(), y: number(), vx: number(), vy: number() })),
}); Room file
Give each joiner ownership, and clamp movement speed server-side:
export default defineRoom(schema, {
onJoin(state, ctx) {
state.players[ctx.clientId] = { x: 0, y: 0, vx: 0, vy: 0, owner: ctx.clientId };
},
validate: {
players(prev, next) {
const max = 16;
next.x = clamp(next.x, prev.x - max, prev.x + max);
next.y = clamp(next.y, prev.y - max, prev.y + max);
return next;
},
},
}); Client
function update(dt: number) {
const me = room.state.players[room.me];
me.x += input.x * SPEED * dt;
me.y += input.y * SPEED * dt;
} Smoothing remote players
Remote entities arrive at the room’s sync rate, not your frame rate. Interpolate toward their latest value for buttery motion:
ghost.x += (target.x - ghost.x) * 0.25;
ghost.y += (target.y - ghost.y) * 0.25; Next steps
Placeholder guide.