Backpedal with a held facing
Goal
Move a fighter away from an opponent while its drawn body keeps facing them. CharacterPawn is a character bundle on the characterMovement kinematic capsule, with walking, jumping and pawn blocking. A held controller yaw is independent of travel direction.
Files you will edit
src/game.ts
Steps
- Start with a game whose manifest already contains a character bundle named
fighter. Keep its host bootstrap. Place two fighters over the existing floor:
ts
import {
CharacterPawn,
addMovementInput,
defineGame,
setDesiredRotation,
spawnActor,
yawToward,
} from 'gameable';
import type { ActorHandle } from 'gameable';
let fighter: ActorHandle;
let opponent: ActorHandle;
const away = { x: 0, y: 0, z: 0 };
export default defineGame({
init(ctx) {
fighter = spawnActor(ctx, CharacterPawn, {
position: { x: -2, y: 0.93, z: 0 },
props: { character: 'fighter', maxWalkSpeed: 2, orientRotationToMovement: false },
});
opponent = spawnActor(ctx, CharacterPawn, {
position: { x: 2, y: 0.93, z: 0 },
props: { character: 'fighter', orientRotationToMovement: false },
});
},
systems: [
(ctx) => {
const from = fighter.position;
const to = opponent.position;
setDesiredRotation(fighter.entity, yawToward(from, to));
setDesiredRotation(opponent.entity, yawToward(to, from));
away.x = from.x - to.x;
away.z = from.z - to.z;
const length = Math.hypot(away.x, away.z);
if (length > 0) {
away.x /= length;
away.z /= length;
}
if (ctx.input.isDown('A')) addMovementInput(fighter.entity, away);
},
],
});- Hold A to retreat. Movement input is consumed on the next actor step.
rotationRatelimits yaw in degrees/second;jumpZVelocitysets jump speed in metres/second (jump(entity)requests it). The actor disables animation carry so main's movement solver owns travel and the take follows its velocity. - The motion layer loops the set's
jog_backtake when available. Otherwise it plays a forward stride at a negative rate while holding the body yaw.setDesiredRotation(entity, undefined)releases the persistent hold. WithorientRotationToMovement: true, travel controls rotation and the held yaw is ignored. Calls tocharacter.setStatewithout facing keep ordinary motion.
Verify
Run the game's usual preview. Hold A: separation increases while both bodies face each other. Release A: the fighter brakes to a stand. Test both a set with jog_back and a forward-only set, then check direct and compiled WASM builds. The optional facing must also survive room replication and a late join.