godot-2d-movement
gamedev-skills/awesome-gamedev-agent-skills
Build responsive 2D character controllers in Godot 4.x with CharacterBody2D and move_and_slide().
What is godot-2d-movement?
Implement 2D kinematic movement for platformers and top-down games using Godot 4.7's CharacterBody2D. Covers gravity, jumping, slope handling, collision detection, and 8-direction motion. Use this when scripting player or enemy controllers that need physics-based movement without rigid bodies.
- Apply gravity and implement jump mechanics for platformer characters
- Handle 8-direction top-down movement with floating motion mode
- Detect floor, wall, and collision states using is_on_floor() and get_slide_collision()
- Slide along slopes and surfaces naturally with move_and_slide()
- Implement coyote time and other jump-feel refinements
- Read collision results to trigger damage, pickups, or other interactions
How to install godot-2d-movement
npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill godot-2d-movement- Godot 4.7 installed
- A scene with a CharacterBody2D node and a CollisionShape2D child
- Input actions defined in Project Settings > Input Map (e.g., move_left, move_right, jump)
How to use godot-2d-movement
- 1.Create a CharacterBody2D node with a CollisionShape2D child in your scene
- 2.Attach a GDScript to the CharacterBody2D
- 3.In _physics_process(delta), set the velocity property based on input and physics (gravity, jump)
- 4.Call move_and_slide() with no arguments to move the body and update velocity
- 5.Use is_on_floor(), is_on_wall(), and get_slide_collision() to read movement results
- 6.Tune exported variables like speed, jump_velocity, and gravity to match your game feel
Use cases
- Scripting a platformer player controller with gravity, jump, and slope walking
- Building a top-down character that moves in 8 directions without gravity
- Detecting when a moving character touches enemies or hazards
- Fixing move_and_slide() behavior when characters sink through floors or is_on_floor() returns false
- Adding forgiving jump timing with coyote time mechanics
- Game developers building 2D platformers or top-down games in Godot 4.x
- Programmers scripting player and enemy controllers
- Developers debugging character movement or collision issues in Godot
godot-2d-movement FAQ
Check that the CollisionShape2D exists and is not zero-sized, the floor body is on a collision layer this character's mask includes, and you are moving via velocity + move_and_slide() rather than position +=.
Verify that up_direction is set correctly (default Vector2.UP), a CollisionShape2D child exists, and you called move_and_slide() this frame. Also check collision layers and masks match.
No. move_and_slide() already accounts for the physics delta internally. Multiplying by delta makes the character crawl. Set velocity directly and let move_and_slide() handle the frame timing.
Use coyote time: track a countdown that resets when is_on_floor() is true, and allow jumping if the countdown is still positive. This lets players jump briefly after leaving a ledge.
Platformer uses gravity (velocity.y increases each frame) and jump input; top-down sets motion_mode to MOTION_MODE_FLOATING and builds velocity from 8-direction input without gravity.
Full instructions (SKILL.md)
Source of truth, from gamedev-skills/awesome-gamedev-agent-skills.
name: godot-2d-movement description: > 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, 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.
Core workflow
- Use
CharacterBody2Dwith aCollisionShape2Dchild. It is script-driven: it does not fall or react to forces on its own. - Set the
velocityproperty, then callmove_and_slide()(no arguments in 4.x). The method readsvelocity, moves the body, slides along surfaces, and updatesvelocityto reflect what actually happened. - Do it in
_physics_process(delta)—move_and_slide()uses the physics step's delta internally, so do not multiplyvelocitybydeltayourself. - Platformer: add gravity to
velocity.yeach tick, jump by settingvelocity.ynegative whenis_on_floor(). - Top-down: build a direction from input and scale by speed; set
motion_mode = MOTION_MODE_FLOATINGso there is no "floor/wall" distinction. - Read results with
is_on_floor(),is_on_wall(),get_wall_normal(), andget_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
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 thevelocityproperty and callmove_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. Settingvelocity = dir * speed * deltamakes the body crawl. - Movement in
_processinstead of_physics_processcauses frame-rate-dependent, jittery motion. Always move in_physics_process. is_on_floor()always false whenup_directionis wrong (defaultVector2.UP), there is noCollisionShape2D, or you never calledmove_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 afloor_snap_lengthso 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), readreferences/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.
Related skills
More from gamedev-skills/awesome-gamedev-agent-skills and the wider catalog.

godot-3d-essentials
Set up Godot 4.7 3D scenes with transforms, cameras, lights, environments, and GridMap.

godot-animation
Animate in Godot 4.x with AnimationPlayer clips, AnimationTree state machines, or Tween procedural effects.

godot-audio
Play, mix, and sync audio in Godot 4.7 with buses, effects, and beat-accurate timing.

godot-csharp
Write Godot 4.7 game code in C# with type-safe nodes, signals as events, and GDScript interop.

godot-export
Export and build Godot 4.x projects for Windows, macOS, Linux, Web, Android, and headless servers.

godot-gdscript
Write idiomatic GDScript 2.0 for Godot 4.7 with static typing, lifecycle callbacks, and signals.