thedivergentai/godot-characterbody-2d
Expert patterns for CharacterBody2D including platformer movement (coyote time, jump buffering, variable jump height), top-down movement (8-way, tank controls), collision handling, one-way platforms, and state machines. Use for player characters, NPCs, or enemies. Trigger keywords: CharacterBody2D, move_and_slide, is_on_floor, coyote_time, jump_buffer, velocity, get_slide_collision, one_way_platforms, state_machine.
npx skills add https://github.com/thedivergentai/GD-Agentic-Skills --skill godot-characterbody-2d
Expert CharacterBody2D feel systems — not beginner move_and_slide tutorials.
RigidBody2D for standard player controllers — RigidBody is for physics-simulated objects. For responsive, feel-driven player movement, always use CharacterBody2D.velocity by delta before move_and_slide() — move_and_slide() handles delta internally. Manual multiplication makes movement framerate-dependent.global_position updates for gameplay movement — Use velocity + move_and_slide(). Direct position hacks bypass collision, floor snap, and one-way rules.position.y — Use one-way collision shapes + layer/mask (and temporary mask disable / collide-with-areas patterns). See godot-2d-physics.move_and_slide() — is_on_floor(), is_on_wall(), is_on_ceiling(), and slide collisions drive coyote, wall jump, and bonk logic.floor_snap_length for fast stair-climbing — Default snapping is too small for high-velocity characters. Use custom raycast-based stair logic.is_on_floor() is true — Constant downward force causes micro-jitter and fights floor-snap. Reset velocity.y on land.Area2D as primary ground detection — Prefer is_on_floor() / shapecasts; Areas are for triggers, not floor truth.velocity.y when is_on_ceiling() or the player floats into the ceiling until gravity wins._process only (subpixel_movement_rounding.gd).queue_free() for hordes — Pool bullets/enemies when spawn/despawn is frequent (performance_character_pooling.gd).CollisionShape2D affects platformer feel — align with movement normals.| Need | Body |
|------|------|
| Feel-driven player / NPC / enemy locomotion | CharacterBody2D |
| Rolling debris, ragdoll-ish props, force piles | RigidBody2D |
| Static level colliders | StaticBody2D / TileMapLayer physics |
| Task | Do First | Then (optional) | Do NOT Load |
|------|----------|-----------------|-------------|
| Platformer foundation (coyote, buffer, accel/friction) | expert_physics_2d.gd | — | Inline tutorial controllers |
| Isolate coyote/buffer only | frame_perfect_coyote_time.gd | — | Duplicate coyote blocks in SKILL |
| Variable jump / short hop | variable_jump_height.gd | — | — |
| Slopes / stairs | slope_stair_snapping.gd | godot-raycasting-queries | — |
| Wall slide / wall jump | wall_slide_jump_refined.gd or wall_jump_controller.gd | — | Both unless comparing |
| Dash + i-frames | dash_state_controller.gd or dash_controller.gd | — | Both unless comparing |
| Air control polish | aerial_drift_acceleration.gd | — | — |
| Ceiling stick / bonk | ceiling_bonk_detection.gd | — | — |
| Knockback / wind impulses | impulse_response_handler.gd | — | — |
| Pixel-art visuals | subpixel_movement_rounding.gd | — | Rounding global_position in physics |
| Many AI bodies | performance_character_pooling.gd | — | — |
| One-way platforms | Tile/StaticBody one-way + layers/masks | godot-tilemap-mastery / godot-2d-physics | position.y += 1 drop-through hacks |
| Top-down / tank locomotion | movement-recipes.md | — | Inline 8-way tutorials |
| Jump arc debug tuning | game_feel_profiler.gd | — | — |
| Animation root motion | root_motion_controller.gd | godot-2d-animation | — |
Golden path: Read expert_physics_2d.gd first. Add dash/wall/jump scripts only after that controller is in place. Do not re-inline coyote/buffer/accel loops in the scene when the script already owns them.
CollisionShape2D one-way / TileSet physics one-way), not by teleporting the player.move_and_slide with position nudges.Monitor is_on_wall() while falling; scale velocity.y by a friction factor (optionally from tile custom data) instead of a binary wall-slide bool. Prefer wall_slide_jump_refined.gd over a bespoke cling fork.
Pull AnimationTree.get_root_motion_position(), convert to 2D, assign velocity = motion / delta, then move_and_slide(). Keeps feet locked to authored clips; pair with godot-2d-animation.
Debug-draw historical positions + current velocity in _draw() to visualize apex, coyote, and buffer windows while tuning exports on expert_physics_2d.gd — game_feel_profiler.gd.
> MANDATORY for top-down/tank recipes, moving platforms, slide-collision response, and gotcha tables: movement-recipes.md. Do NOT Load when expert_physics_2d.gd already covers your platformer scope.
> Progressive disclosure: open Official Documentation links only when researching a specific API;
> load Related Skills when routing work to a peer domain — do not preload the whole lattice.
move_and_slide / floor-wall-ceiling contracts; do not set position for gameplay motion.velocity, snap, is_on_floor / wall / ceiling, and slide-collision accessors.CollisionShape2D nodes corrupt normals and floor detect.is_on_floor().get_slide_collision for wall jumps and ceiling bonks._physics_process, timers, and move_toward discipline underpin every movement script here.is_on_* helpers.move_and_slide._physics_process switches.velocity + slide loop.Take thedivergentai/godot-characterbody-2d from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.