Install
$ agentstack add skill-gamedev-skills-awesome-gamedev-agent-skills-godot-2d-movement ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Godot 2D Movement (4.x)
Build responsive 2D character controllers with CharacterBody2D and the argument-less move_and_slide(). Targets Godot 4.3+.
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
- 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 reads velocity, moves the body, slides along surfaces, and updates velocity to reflect what actually happened.
- Do it in
_physics_process(delta)—move_and_slide()uses the physics step's
delta internally, so do not multiply velocity by delta yourself.
- Platformer: add gravity to
velocity.yeach tick, jump by settingvelocity.y
negative when is_on_floor().
- Top-down: build a direction from input and scale by speed; set
motion_mode = MOTION_MODE_FLOATING so there is no "floor/wall" distinction.
- 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
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
_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 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.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: gamedev-skills
- Source: gamedev-skills/awesome-gamedev-agent-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.