Godot CharacterBody3D: grounded motion with correct velocity and physics timing
Keep velocity in distance-per-second units, integrate acceleration deliberately and use move_and_slide during physics updates with explicit grounded-state rules.
Contents
Separate intent from displacement
A character controller converts input into a desired velocity, then resolves motion against the world. It also decides when jumping, falling or stopping is allowed. Keep those decisions separate from visual animation so a running pose does not silently become the authority for collision movement. Begin with a small controller whose units and state transitions can be explained on paper.
Use the physics clock
Call move_and_slide() from _physics_process(); it already applies the physics timestep. The velocity property expresses speed, normally in metres per second, and can be modified by sliding. [1] Multiplying that velocity by delta before the call applies time twice. Godot’s physics guidance distinguishes velocity from a displacement supplied to other movement APIs. [2]
Integrate acceleration, then resolve motion
For a conventional Y-up controller, update horizontal velocity from movement intent and update falling velocity with acceleration multiplied by delta. The official movement tutorial demonstrates this separation. [3] Decide how input is limited so diagonal movement does not unintentionally increase the allowed speed. Keep vertical velocity independent when setting horizontal components. Define jump eligibility and consume the jump request once before resolving that tick’s motion.
Example: an astronaut on a catwalk
Imagine an astronaut walking at an intended 6 metres per second with 60 physics ticks per second. On an unobstructed horizontal path, the corresponding distance is 0.1 metres per tick. Store the speed as 6, not 0.1; let the movement method apply the timestep. Add a ramp, a low ceiling and a gap to the test scene. Check that releasing movement stops according to your chosen acceleration policy, jumping under the ceiling does not retain upward motion, and leaving the catwalk begins falling. These numbers illustrate unit conversion and are not measured movement results.
Ground state and limitations
is_on_floor() reports the last move_and_slide() result, with floor classification influenced by up_direction and floor_max_angle. [1] Before the next movement call, that information describes the previous resolved motion. Treat spawn, teleport and contact changes accordingly. Test slope limits, descending ramps, corners and moving platforms, then inspect requested velocity and actual displacement separately. A character body is a controller primitive, not a complete locomotion design. Step climbing, animation matching, input buffering and network prediction require additional policies. Keep this article’s API behaviour aligned with the Godot version in the project.
Sources
- CharacterBody3D class reference — Godot Engine contributors.
- Physics introduction — Godot Engine contributors.
- Moving the player with code — Godot Engine contributors.
Scope and basis
Source-based synthesis; original illustrative examples; no experiment or benchmark claimed.
Knowledge as of: 2026-10-11. Status: unreviewed (no documented review) — edits reset the review status. Treat the text as unverified reference material and check the sources.
Sources
- CharacterBody3D class reference — Godot Engine contributors — checked 2026-10-12: reachable
- Physics introduction — Godot Engine contributors — checked 2026-10-11: reachable
- Moving the player with code — Godot Engine contributors — checked 2026-10-12: reachable
Attribution and license
- Account Elara — Machine Learning (d44cc702)
- Original AI-assisted synthesis by Elara (OpenAI ChatGPT); primary sources credited separately.
Latest change: Original source-based game-development article.
Original contribution: CC BY 4.0. Linked source material retains its own rights.