CharacterBody3D is a physics body specialized for characters moved by script. It ignores incoming forces while pushing other bodies out of its way. This post covers setting up a CharacterBody3D, configuring motion modes, and writing movement logic with move_and_slide() in Godot 4.2, starting from an empty 3D project.

The Problem With Other Physics Bodies

RigidBody3D responds to gravity and collisions automatically. You lose direct control over the character's motion. StaticBody3D never moves on its own. Neither fits user-controlled characters that need wall sliding, floor detection, and jumping.

CharacterBody3D fills the gap. You set a velocity vector each frame. The engine handles collision resolution through move_and_slide(). The body affects other physics objects in its path but receives no forces itself.

For simple moving platforms or animated obstacles, AnimatableBody3D requires less configuration. Use CharacterBody3D only when the character needs complex slope handling and platform interaction.

Scene Tree

Player (CharacterBody3D)
├── MeshInstance3D, visible character model
└── CollisionShape3D, capsule shape matching the model

The CollisionShape3D must be a direct child of CharacterBody3D. Add it through the menu bar: Scene → Insert Scene, then add a CapsuleGeometry3D as the shape resource.

Motion Modes

motion_mode changes how move_and_slide() treats surfaces. Set it in the Inspector before runtime testing.

  • Motion Mode: Grounded, distinguishes floor, wall, and ceiling. Slopes cause acceleration or slowdown. Use for platformers and grounded third-person games.
  • Motion Mode: Floating, every surface counts as a wall. Speed stays constant during slides. Use for space ships and flying cameras.

In floating mode, is_on_floor() always returns false. The Up Direction property is ignored entirely.

Key Properties

Configure these before testing movement. Leave others at default unless the character exhibits specific symptoms.

  • Velocity: Vector3(0, 0, 0), current speed and direction. Set this every frame before calling move_and_slide()
  • Up Direction: Vector3(0, 1, 0), determines which way is "up" for floor and wall classification
  • Floor Max Angle: 0.785398, maximum slope angle in radians treated as ground. Default equals 45 degrees. Values above this treat slopes as walls
  • Floor Snap Length: 0.1, distance used to stick the body to slopes during movement. Zero disables snapping entirely
  • Max Slides: 6, how many times the body can change direction per frame during collision. Higher values cost performance
  • Safe Margin: 0.001, extra buffer applied before actual motion begins. Increase if the character clips through thin walls. Decrease if jitter appears on small geometry

Floor and Wall Behavior Flags

  • Floor Block On Wall: true, prevents walking vertically along walls. The body still slides downward against them
  • Floor Constant Speed: false, when disabled, upward slopes slow the character and downward slopes accelerate it. Enable for uniform ground speed
  • Floor Stop On Slope: true, prevents idle sliding when standing on inclines. Disable if the character should naturally drift downhill
  • Slide On Ceiling: true, lets the character slide sideways when pressed against a ceiling during a jump. Disable for vertical drop-off behavior

Movement Method

move_and_slide() reads the Velocity property, moves the body, resolves collisions, and updates Velocity with any remaining momentum after sliding. Call it once per frame in _physics_process().

The method returns true if a collision occurred during movement. After a collision, get_last_slide_collision() provides details about the hit surface including normal vector and position. Multiple collisions are tracked via get_slide_collision_count() and get_slide_collision(index).

Surface Detection Methods

After move_and_slide() executes, these return the result of the last check:

Method Returns true when...
is_on_floor() Bottom of the collider touches ground within Floor Max Angle
is_on_ceiling() Top of the collider presses against a surface
is_on_wall() Side of the collider contacts a surface outside the floor angle
is_on_floor_only() Floor contact exists with no other surfaces touching
is_on_ceiling_only() Only ceiling contact, nothing else
is_on_wall_only() Only wall contact, no floor or ceiling

Calling any of these before move_and_slide() in the same frame returns stale data from the previous frame. Always move first, check surface state second.

Complete Player Movement

This example implements running, jumping, and falling. Attach it directly to the CharacterBody3D node.

extends CharacterBody3D

@export var speed: float = 5.0
@export var jump_velocity: float = 4.5
@export var fall_speed: float = 15.0

var gravity: Vector3 = Vector3.ZERO

func _physics_process(delta: float) -> void:
	if not is_on_floor():
		gravity.y -= fall_speed * delta
	
	var input_dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
	var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	
	velocity.x = direction.x * speed
	velocity.z = direction.z * speed
	
	if Input.is_action_just_pressed("jump") and is_on_floor():
		velocity.y = jump_velocity
	
	move_and_slide()

After adding input actions for move_left, move_right, move_up, move_down, and jump in Project Settings, the character walks toward input direction and jumps off surfaces. If the character passes through the floor, increase Floor Snap Length to at least 0.15. If the character jitters on flat ground, reduce Safe Margin toward 0.0005.

Platform Interaction

Moving platforms require CharacterBody3D to track their velocity. When the character steps onto a moving platform, the platform's speed adds to the character's motion automatically.

Three behaviors control what happens when leaving a platform:

  • Platform On Leave: Add Velocity, the platform's final velocity transfers to the character. Stepping off a downward-moving platform makes the character continue dropping faster
  • Platform On Leave: Add Upward Velocity, only positive platform motion transfers. Jump height stays consistent regardless of platform direction
  • Platform On Leave: Do Nothing, platform motion has no effect on departure. Useful if you handle platform transitions manually

Control which nodes count as platforms through layer masks:

  • Platform Floor Layers: collision layers checked below the character. Default includes all layers
  • Platform Wall Layers: collision layers checked beside the character. Default excludes all layers. Set this to make elevator shafts carry the character laterally

Retrieving Collision Details

Debug movement issues by inspecting collision data after move_and_slide() reports a hit.

extends CharacterBody3D

@export var speed: float = 5.0

func _physics_process(delta: float) -> void:
	velocity.x = speed
	
	var collided := move_and_slide()
	
	if collided:
		var collision := get_last_slide_collision()
		print("Hit normal: ", collision.get_normal())
		print("Hit point: ", collision.get_position())
		print("Total slides this frame: ", get_slide_collision_count())
	
	print("Real velocity: ", get_real_velocity())

get_real_velocity() returns the actual diagonal movement when climbing slopes, not the horizontal value you assigned to Velocity. Use it for animating foot placement or adjusting camera angle based on true travel direction.

get_floor_normal() and get_floor_angle() provide the ground's orientation at the collision point. Both require is_on_floor() to be true immediately after move_and_slide().

Tuning Common Problems

Character sinks into the floor. Increase Floor Snap Length from 0.1 to 0.2. Ensure the collision shape extends below the visual mesh by at least 0.05 units.

Character gets stuck on corners. Raise Max Slides from 6 to 8. If the corner is very sharp, consider chamfering the geometry, no number of slides resolves a perfect right-angle catch reliably.

Character accelerates uncontrollably on down-slopes. Enable Floor Constant Speed. Combine with a non-zero Floor Snap Length so the body sticks to steep descents rather than detaching mid-slide.

Character refuses to climb gentle slopes. Raise Floor Max Angle beyond the default 0.785398 (45 degrees). A value of 1.2 allows slopes up to roughly 69 degrees. Very high angles make stairs feel like ramps.

Character clips through thin walls or floors. Increase Safe Margin to 0.005 or higher. The collision system detects proximity earlier and pushes away before penetration occurs.

Conclusion

A CharacterBody3D gives you full frame-by-frame control over character motion while retaining automatic wall sliding, floor detection, and platform tracking. The tradeoff is manual velocity management, gravity, acceleration curves, and braking must be written in script. Use it for player characters and AI agents with scripted movement. For objects driven by animation tracks or timeline nodes, AnimatableBody3D removes the velocity bookkeeping overhead.