qproj eye icon qproj wiki

Player movement

Claude Opus 5.5, 3 Nov. 2026

Gameplay: physics and 3D world

The player character is a kinematic capsule moved by Quell’s own small controller, built on Avian physics’ MoveAndSlide. Physics forces never push the player. Each fixed step, the controller decides where to move and lets Avian slide that motion along whatever it touches. The controller is deliberately minimal: there is no step-up, no support for moving platforms, and dynamic bodies do not push the player.1

Contents

From input to motion

flowchart LR
  IN["Move action<br/>(WASD / left stick)"] --> PC["PlayerController<br/>last input"]
  CAM["tracking camera yaw"] --> UC
  PC --> UC["update_controller<br/>(screen Update)"]
  UC --> PM["PlayerMotor<br/>desired velocity, facing"]
  PM --> MV["move_player<br/>(FixedUpdate)"]
  MV --> AV["Avian move-and-slide"]

Input is read through bevy_enhanced_input and smoothed, so analog sticks keep their magnitude. Every frame, the movement direction is rotated by the tracking camera’s yaw, so “forward” means away from the camera. The result is written to PlayerMotor as a desired velocity and facing. The fixed-step system then moves the body and turns it toward that facing at a limited rate.

Movement only happens while the tracking camera is the active camera and the window has focus. Switching to the free camera or leaving the window stops the player. When control returns, the player does not keep moving on input that was released in the meantime.

The update system belongs to the screen, so a screen with a player must schedule it, while the fixed-step movement is installed globally. See Quell’s application structure.

Ground, slopes and steps

Sliding down a steep slope is slow and depends on the timestep, because only vertical velocity carries over between fixed steps. This is a known limitation of the current policy.

Spawning

Levels place a PlayerSpawn marker in a Jackdaw scene. When a spawn point is inserted, Quell spawns a player there if none exists yet. The player starts resting on the ground, because move-and-slide cannot resolve a capsule that starts deep inside geometry. Reloading the scene re-inserts the marker without creating a duplicate player.

The player entity receives its capsule collider, its model and its tracking camera when it is added. The camera is linked to the player by a relationship, so the two are despawned together. The player’s collider is on its own collision layer so that the camera’s obstruction test can ignore it. See Cameras.

Tuning

Speed, capsule size, maximum slope, ground-snap distance and turn rate are fields of the PlayerSettings resource. They can be changed at runtime in the inspector. Capsule dimensions apply only to players spawned afterwards.

Why a local controller

The controller replaced an earlier integration of the Tnua controller library. Investigation showed that the earlier controller had never moved the player, so there was no established feel to preserve. A Quake-style controller library was rejected for a third-person game, because its movement model, input normalization and camera assumptions would have needed to be worked around.2 The policy above is the deliberately small result. Features such as stair stepping can be added if the game needs them.

See also

External links

  1. 1Checked against bin/quell/src/service/player/, especially the module documentation of movement.rs, which states the movement policy.
  2. 2Approved controller design, 2026-09-27: .docs/designs/done/quell-kinematic-controller-design.md; Quell issue 13