Walk with character movement
Goal
Use characterMovement for guest-owned walking, floor checks, steps, sliding, jumping and falling. It creates a kinematic capsule root: another pawn's sweep can hit it. Use characterBody for the existing host-owned Jolt character controller and its physics.moveCharacter command instead.
The example below builds a fixed-camera top-down room with tile walls and an NPC that blocks the player. All distances are metres. Use Pawn on both player and NPC capsules, and BlockAll on floor and walls. OverlapAll is for sensors, not walls; NoCollision supplies no blocking geometry.
Files you will edit
src/game.ts
Steps
- Copy a scaffold and replace its
src/game.tswith the following. Keep the scaffold's existing asset manifest and host bootstrap.
ts
import {
addMovementInput,
box,
characterMovement,
defineActor,
defineGame,
spawnActor,
spawnTileColliders,
} from 'gameable';
const Walker = defineActor('Walker', {
components: { root: characterMovement({ maxWalkSpeed: 3, collision: 'Pawn' }) },
});
const Floor = defineActor('Floor', {
components: { root: box([6, 0.5, 6], { collision: 'BlockAll' }) },
});
const wish = { x: 0, y: 0, z: 0 };
const eye = { x: 0, y: 12, z: 8 };
const target = { x: 0, y: 0, z: 0 };
const rotation = { x: 0, y: 0, z: 0, w: 1 };
let player = 0;
export default defineGame({
init(ctx) {
spawnActor(ctx, Floor, { position: { x: 0, y: -0.5, z: 0 } });
spawnTileColliders(
ctx,
[
{ x: -3, z: -3, height: 2 },
{ x: -2, z: -3, height: 2 },
{ x: -1, z: -3, height: 2 },
{ x: 0, z: -3, height: 2 },
{ x: 1, z: -3, height: 2 },
{ x: 2, z: -3, height: 2 },
],
{ collision: 'BlockAll' },
);
player = spawnActor(ctx, Walker, { position: { x: 0, y: 0.93, z: 2 } }).entity;
spawnActor(ctx, Walker, { position: { x: 0, y: 0.93, z: 0 } });
ctx.camera.set(eye, rotation);
ctx.camera.lookAt(target);
},
systems: [
(ctx) => {
const axis = ctx.input.axis2('A', 'D', 'S', 'W');
wish.x = axis.x;
wish.z = -axis.y;
addMovementInput(player, wish);
},
],
});- Input accumulates until the next actor step, then is consumed once and clamped to length one. Submit AI input the same way for a moving NPC.
jump(entity)requests one jump;stopMovementImmediately(entity)clears velocity and pending input.launchCharacternames its options using a Z-up convention:xyOverridereplaces world X/Z, andzOverridereplaces world Y. - For an orbit camera, possess this actor with your
PlayerControllerand usecreateThirdPersonController. It detects the component automatically. Walk speed comes frommaxWalkSpeed; holding Shift applies the controller'srunSpeed / walkSpeedrule ratio.movementOf(entity)reports actual velocity, walking/falling mode and cached floor. Rotation defaults to following travel at 540 degrees/second; setorientRotationToMovement: falsefor manual facing.
Verify
Run npm run dev. Walk into the wall and NPC: neither should be passable. Release movement: the player brakes to rest. Spawn the NPC elsewhere to confirm that the obstacle was its capsule. With a third-person controller, jump and check that movementOf(entity)?.isFalling becomes true and returns to false when the capsule lands.
The production host must provide actual overlap contact points/depths and exclude the mover before choosing a sweep hit. Older hosts that approximate these values cannot guarantee recovery from an overlapping spawn.