← Back to list
⚡

godot-2d-movement Checked

Implement 2D kinematic character movement in Godot 4.7 with CharacterBody2D and move_and_slide():…
⚡ Productivity skills By gamedev-skills Version v1.0.0 Added 2026-10-21 Updated 2026-10-21 Source ↗
7.7Overall rating
0Views
0Downloads
2.0kStars

Installation

🤖 Install via AI

Copy the prompt below and send it to your AI assistant (e.g. Claude Code) — it will follow the instructions and install automatically.

Install the "godot-2d-movement" skill by following the instructions at https://skill123.me/install/godot-2d-movement.
⌨️ Command line install

Run in your terminal — downloads and installs to ~/.claude/skills/.

curl -fsSL https://skill123.me/install/godot-2d-movement.sh | bash
📦 Download ZIP

Download the zip and extract it into your skills directory (e.g. ~/.claude/skills/), then restart your session.

⬇ Download v1.0.0 · 4 KB
📊 Static rating
7.7/10
Trigger
8.0
Structure
0.0
Workflow
8.0
Content
0.0
Engineering
0.0
Security
7.0

Six-dimension rubric with reviewer rationale.

View scorecard ↓
🛡 Dynamic test
—

Not live-tested yet — this skill is rated on static analysis only.

About this skill

Implement 2D kinematic character movement in Godot 4.7 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.

Godot 2D Movement (4.x)

Build responsive 2D character controllers with CharacterBody2D and the argument-less

move_and_slide(). Targets **Godot 4.7**.

Documentation

Implement 2D kinematic character movement in Godot 4.7 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.

Godot 2D Movement (4.x)

Build responsive 2D character controllers with CharacterBody2D and the argument-less

move_and_slide(). Targets **Godot 4.7**.

When to use

  • Use when scripting a 2D player/enemy that moves and collides: platformer (gravity +

jump) or top-down (free 8-direction), slope walking, or wall/floor detection.

  • Use when move_and_slide() "does nothing", the character sinks through floors, or

is_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.

Core workflow

1. **Use CharacterBody2D** with a CollisionShape2D child. It is script-driven: it

does not fall or react to forces on its own.

2. **Set the 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.

3. **Do it in _physics_process(delta)** — move_and_slide() uses the physics step's

delta internally, so do not multiply velocity by delta yourself.

4. **Platformer:** add gravity to velocity.y each tick, jump by setting velocity.y

negative when is_on_floor().

5. **Top-down:** build a direction from input and scale by speed; set

motion_mode = MOTION_MODE_FLOATING so there is no "floor/wall" distinction.

6. **Read results** with is_on_floor(), is_on_wall(), get_wall_normal(), and

get_slide_collision(i) after the call.

Patterns

### 1. Platformer controller (gravity, jump, slopes)


extends 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`

### 2. Top-down 8-direction movement


extends CharacterBody2D

@export var speed := 220.0
View full documentation

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()



### 3. Reading slide collisions after moving

func _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



### 4. Coyote time (forgiving jump just after leaving a ledge)

@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() ...



## Pitfalls

- **3.x signature is gone.** `move_and_slide(velocity)` (returning the new velocity) was
  removed. In 4.x set the `velocity` property and call `move_and_slide()` with no args.
  `move_and_slide(velocity, Vector2.UP)` will not parse.
- **Multiplying velocity by delta.** `move_and_slide()` already accounts for the physics
  delta. Setting `velocity = dir * speed * delta` makes the body crawl.
- **Movement in `_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.
- **Sinking through floors** usually means the collision shape is missing/zero-sized, the
  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()`.
- **Slope slipping while idle:** keep `floor_stop_on_slope = true` (default) and set a
  `floor_snap_length` so the body sticks to downward slopes.

## References

- For one-way platforms, moving platforms, jump buffering, variable jump height, and
  `move_and_collide()` (manual collision response), read `references/controller-recipes.md`.

## Related skills

- `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.

Score breakdown

Trigger
8.0
Structure
0.0
Workflow
8.0
Content
0.0
Engineering
0.0
Security
7.0