Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implement 2D kinematic character movement in Godot 4.x with CharacterBody2D and move_and_slide(): platformer run/jump with gravity, top-down 8-direction motion, slope handling, and reading collisions. Use when coding a 2D player or enemy controller, a platformer or top-down character, or fixing move_and_slide()/ is_on_floor() behavior in a .tscn with a CharacterBody2D.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-14 | ✓→✗ | ▼ Worse | 76% | 0% |
| case-21 | ✓→✗ | ▼ Worse | 52% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 48% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 139% | 0% |
Build responsive 2D character controllers with CharacterBody2D and the argument-less move_and_slide(). Targets Godot 4.3+.
jump) or top-down (free 8-direction), slope walking, or wall/floor detection.
move_and_slide() "does nothing", the character sinks through floors, oris_on_floor() is always false.
When not to use: dynamic rigid bodies, areas, raycasts, collision layers → godot-physics; tile-based levels → godot-tilemap; full platformer game template → the platformer genre skill; engine-agnostic feel tuning → physics-tuning.
CharacterBody2D with a CollisionShape2D child. It is script-driven: itdoes not fall or react to forces on its own.
velocity property, then call move_and_slide() (no arguments in 4.x).The method reads velocity, moves the body, slides along surfaces, and updates velocity to reflect what actually happened.
_physics_process(delta) — move_and_slide() uses the physics step'sdelta internally, so do not multiply velocity by delta yourself.
velocity.y each tick, jump by setting velocity.ynegative when is_on_floor().
motion_mode = MOTION_MODE_FLOATING so there is no "floor/wall" distinction.
is_on_floor(), is_on_wall(), get_wall_normal(), andget_slide_collision(i) after the call.
gdscriptextends CharacterBody2D @export var speed := 200.0 @export var jump_velocity := -400.0 @export var gravity := 1200.0 # pixels/sec^2 (tune to taste) func _physics_process(delta: float) -> void: # Apply gravity while airborne. if not is_on_floor(): velocity.y += gravity * delta # Jump only when grounded (Input action set in Project Settings > Input Map). if Input.is_action_just_pressed("jump") and is_on_floor(): velocity.y = jump_velocity # Horizontal input: -1, 0, or 1. var dir := Input.get_axis("move_left", "move_right") if dir != 0.0: velocity.x = dir * speed else: velocity.x = move_toward(velocity.x, 0.0, speed) # decelerate to a stop move_and_slide() # 4.x: no arguments; uses and updates `velocity`
gdscriptextends CharacterBody2D @export var speed := 220.0 func _ready() -> void: motion_mode = CharacterBody2D.MOTION_MODE_FLOATING # no floor/ceiling concept func _physics_process(_delta: float) -> void: # get_vector returns a normalized-ish Vector2 from four input actions. var input := Input.get_vector("move_left", "move_right", "move_up", "move_down") velocity = input * speed move_and_slide()
gdscriptfunc _physics_process(delta: float) -> void: # ... set velocity ... move_and_slide() for i in get_slide_collision_count(): var c := get_slide_collision(i) var other := c.get_collider() if other and other.is_in_group("enemies"): take_damage(1) # touched an enemy while moving
gdscript@export var coyote_time := 0.1 var _coyote := 0.0 func _physics_process(delta: float) -> void: if not is_on_floor(): velocity.y += gravity * delta _coyote -= delta else: _coyote = coyote_time if Input.is_action_just_pressed("jump") and _coyote > 0.0: velocity.y = jump_velocity _coyote = 0.0 # ... horizontal input + move_and_slide() ...
move_and_slide(velocity) (returning the new velocity) wasremoved. In 4.x set the velocity property and call move_and_slide() with no args. move_and_slide(velocity, Vector2.UP) will not parse.
move_and_slide() already accounts for the physicsdelta. Setting velocity = dir * speed * delta makes the body crawl.
_process instead of _physics_process causes frame-rate-dependent,jittery motion. Always move in _physics_process.
is_on_floor() always false when up_direction is wrong (default Vector2.UP),there is no CollisionShape2D, or you never called move_and_slide() this frame.
floor body is on a layer this body's mask doesn't include, or you moved the body via position += instead of velocity + move_and_slide().
floor_stop_on_slope = true (default) and set afloor_snap_length so the body sticks to downward slopes.
move_and_collide() (manual collision response), read references/controller-recipes.md.
godot-physics — collision layers/masks, areas, raycasts, rigid bodies.godot-tilemap — building the levels this character walks on.godot-animation — driving sprite/skeletal animation from movement state.camera-systems — follow camera, deadzone, and look-ahead that track this character.platformer / input-systems — full genre template and rebindable input.Other measured skills in the registry, with their headline benchmark lift.