logo
Movement

movement

Movement

Free

Install with the CLI:

bjs download Movement

Movement

Kinematic character movement — walk, turn-to-face, jump, and ground-snap on a flat floor.

What it does

Each frame MovementSystem reads a character's intent (a move vector plus an edge-triggered jump) out of its MovementComponent, reads the mesh's current world position from the renderer, and feeds both into a pure core that integrates gravity, applies the jump impulse, snaps the feet to groundY, and steps the yaw toward the direction of motion. It writes the resulting position (and, when faceMotion is on, the yaw) back to the mesh. Intent arrives two ways: mutate moveX / moveZ / jumpPressed directly (script or AI), or fire input.movement.vector and input.jump.requested on the EventBus. As gameplay events occur the System emits movement.jump.started, movement.grounded.changed, movement.started, and movement.stopped, so animation, audio, and camera can react without holding a reference to the character.

Use it in a scene

A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.

Fastest path

bjs download scene Movement

Pulls this exact scene into your project and runs it — no copy-paste. Add --all to grab the components and assets it needs too.

Or build it from scratch with the bjs CLI:

  1. 1Scaffold a project
    npm create @babylonjsmarket/arcade@latest my-game

    World, renderer, and dev server — ready to run.

  2. 2Install dependencies
    cd my-game && npm install
  3. 3Add Movement
    bjs download Movement

    Copies its source into src/ so the scene resolves.

    First time? Run bjs login once.

  4. 4Paste the scene into src/scenes/arcade-room.ts and run
    npm run dev

    SceneLoader builds the world from the JSON; reload to rebuild.

JSON
{
  "Hero": {
    "tags": ["player"],
    "components": {
      "MeshPrimitive": {
        "primitive": "capsule",
        "radius": 0.5,
        "height": 2,
        "position": [0, 1, 0]
      },
      "Movement": {
        "speed": 5,
        "jumpForce": 8,
        "gravity": 20,
        "groundY": 0
      }
    }
  }
}

Props

  • speed (number, default 5) — horizontal speed at full input, world units/sec.
  • rotationSpeed (number, default Math.PI * 2) — yaw turn rate toward the direction of motion, radians/sec.
  • jumpForce (number, default 8) — upward velocity applied on a grounded jump, world units/sec.
  • gravity (number, default 20) — downward acceleration while airborne, world units/sec².
  • feetOffset (number, default 1) — distance from the pivot down to the feet (capsule half-height); the pivot snaps to groundY + feetOffset.
  • maxFallSpeed (number, default 50) — terminal fall speed cap; 0 = uncapped.
  • faceMotion (boolean, default true) — when true, the mesh yaws to face its horizontal direction of motion.
  • groundY (number | null, default 0) — world Y of the floor under the character (flat-floor assumption). null disables grounding entirely — the character falls forever.
  • position ([x,y,z], default [0, feetOffset, 0]) — initial pivot position, used only when the entity has no mesh to seed from.

Events

  • Emits movement.jump.started (MovementEvents.JUMP_STARTED) — { entityId }, the frame the character leaves the ground via jump.
  • Emits movement.grounded.changed (MovementEvents.GROUNDED_CHANGED) — { entityId, isGrounded }, whenever the grounded state flips.
  • Emits movement.started (MovementEvents.STARTED_MOVING) — { entityId }, on the still-to-moving transition.
  • Emits movement.stopped (MovementEvents.STOPPED_MOVING) — { entityId }, on the moving-to-still transition.
  • Listens for input.movement.vector (MovementInputEvents.SET_MOVEMENT_VECTOR) — { entityId, x, y?, z }, XZ plane only; sets moveX / moveZ.
  • Listens for input.jump.requested (MovementInputEvents.JUMP_REQUESTED) — { entityId }; sets jumpPressed for the next tick.

Dependencies

MeshPrimitive — the mesh this System moves. Each frame it reads that mesh's world position before integrating and writes the new position back, so external systems (shadows, collisions) that nudged the mesh are respected.

Notes

  • The move vector is clamped to a unit disc inside the core, so a diagonal (1, 1) isn't faster than a straight (1, 0).
  • The jump is edge-triggered: jumpPressed is consumed and reset to false after each tick, and a jump only fires while grounded — buffering a press across multiple frames is the caller's job.
  • With groundY set, the feet snap to the floor only while descending (velY <= 0), so an in-flight character clears low ledges without sticking.
  • Set groundY to null for pits and ledges where the character should fall off the edge; the renderer can swap in a per-frame raycast hit Y for non-flat terrain.

More like this

BallPursuit
MeshPrimitive
Physics
PlayerInputBridge
AiDriver
AiPilot
Animation
ArcCamera
Asteroid
BoatMode
Bullet
CameraFollow
CarDrive
DirectionalLight
EnemySpawner
EnvironmentTexture
FreighterCar
FreighterChain
FreighterHead
GameConfig
Health
HemisphericLight
Jump
KeyboardInput
KeyboardMover
Lifetime
LineOfSight
MachineGun
Mesh
Missile
MissileLauncher
MissionDirector
MouseInput
Obstacle
ObstacleField
OilBlob
Parts
PlayerInput
PlayerWalkAnimator
RespawnTimer
RoundReset
Score
Shadow
ShipFlight
ShipLoadout
SkeletonAnimator
SpaceShooterBullet
SpaceShooterHealth
SpaceShooterScore
TrafficConvoy
Transform6DOF
TwinStickEnemy
Velocity6DOF
WaveDirector
Waypoint
WaypointTrack
WorldOriginAnchor

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search