thedivergentai/godot-2d-physics
Expert patterns for Godot 2D physics including collision layers/masks, Area2D triggers, raycasting, and PhysicsDirectSpaceState2D queries. Use when implementing collision detection, trigger zones, line-of-sight systems, or manual physics queries. Trigger keywords: CollisionShape2D, CollisionPolygon2D, collision_layer, collision_mask, set_collision_layer_value, set_collision_mask_value, Area2D, body_entered, body_exited, RayCast2D, force_raycast_update, PhysicsPointQueryParameters2D, PhysicsShapeQueryParameters2D, direct_space_state, move_and_collide, move_and_slide.
npx skills add https://github.com/thedivergentai/GD-Agentic-Skills --skill godot-2d-physics
Expert guidance for collision detection, triggers, and raycasting in Godot 2D.
CollisionShape2D nodes — Use the shape handles in the editor, NOT the Node2D scale property. Scaling causes unpredictable physics behavior and incorrect collision normals [12].collision_layer with collision_mask — Layer = "What AM I?", Mask = "What do I DETECT?". Setting both to the same value is usually wrong [13].move_and_slide() — move_and_slide() automatically includes timestep. Only multiply gravity/acceleration by delta [14].force_raycast_update() for manual mid-frame raycasts — Raycasts update once per physics frame. If you change target_position, you MUST force an update [15].get_overlapping_bodies() every frame — It is expensive. Cache results with body_entered/body_exited signals instead [16].RigidBody2D state directly in _process — Use _integrate_forces() for safe, synchronized access to PhysicsDirectBodyState2D [17, 411].PhysicsBody2D nodes in _process() — Use _physics_process(). Moving bodies outside the physics step causes stutter and unreliable collision detection.RigidBody2D for 1000+ simple entities — Use PhysicsServer2D to bypass node overhead for massive performance gains (Swarms/Bullets) [18, 397].Area2D for high-frequency blocking (Bullets) — Area signals can be delayed. Use move_and_collide() or ShapeCast2D for frame-perfect results [19].set_deferred for immediate physics transform logic — It happens at the end of the frame. Use force_raycast_update() or PhysicsServer2D instead.PhysicsServer2D RIDs manually — They are not garbage collected and will leak memory permanently.body_set_shape_as_one_way_collision adds direction parameter — set relative to shape orientation for one-way platforms.CollisionShape2D supports one-way collision direction relative to the shape (not just global up).> MANDATORY: Read the script matching your workflow branch before coding. Query/Area cookbook samples live in scripts — not in this body.
| Branch | Load | Do NOT Load |
|--------|------|-------------|
| Layer/mask matrix setup | collision_bitmask_helper.gd or collision_setup.gd; matrix policy → collision_layer_matrix_manager.gd | Swarm / CCD scripts |
| LOS / vision cones | raycast_vision_stack.gd (+ physics_direct_query.gd for nodeless rays) | shapecast_aoe*.gd, physics_server_swarm.gd |
| AOE / melee volume | Prefer shapecast_aoe.gd (faction mask); ground/volume sensing → shapecast_aoe_detection.gd | Area2D spam + lava DoT tutorials; do not load both shapecast scripts for the same feature |
| Hitscan / point pick / one-shot shape | physics_queries.gd (canonical). Specialists: physics_direct_space_query.gd (LOS bool), raycast_hit_prediction.gd | Re-load all three query helpers at once |
| Bullet hell / 1000+ bodies | MANDATORY physics_server_swarm.gd (+ physics_server_direct_body.gd for RID shapes) | Per-bullet Area2D / RigidBody2D nodes |
| High-speed tunneling | continuous_collision_detection.gd + substepping_logic.gd | CCD on slow props |
| RigidBody safe mutate | safe_rigidbody_state.gd (_integrate_forces) | Direct transform writes in _process |
| Custom CharacterBody forces | custom_physics_2d.gd | custom_physics.gd (that file is RigidBody _integrate_forces) |
| Gravity zones | custom_gravity_area.gd (Area override) or custom_gravity_override.gd (character weight/zones) | Both unless you need Area + character paths |
| Overlap signal spam | collision_debouncer.gd | Polling get_overlapping_bodies every frame |
| Compound multi-shape RID | compound_body_sync.gd | Multiple nodes for one logical body |
| Debug contact normals | collision_visual_debugger.gd | Visible collision menu insufficient |
| High-refresh jitter | Prefer jitter_interpolation_fix.gd | physics_interpolation_smoothing.gd (legacy/manual; only if built-in interpolation is unavailable) |
| Precision bounce / slide | move_and_collide_precision.gd | — |
| Batch static movers | performance_batch_mover.gd | — |
| Query result cache | physics_query_cache.gd | Duplicate space queries same frame |
shapecast_aoe.gd for combat AOE; shapecast_aoe_detection.gd only for grounded/volume checks — never both for one feature.physics_queries.gd; add physics_direct_query.gd / physics_direct_space_query.gd only if that specialist matches.custom_physics_2d.gd; RigidBody integrate → custom_physics.gd.jitter_interpolation_fix.gd wins over physics_interpolation_smoothing.gd.| Use Case | Method | Why / script |
|----------|--------|--------------|
| Continuous trigger zone | Area2D + signals | Memory of occupants; debounce with collision_debouncer.gd |
| One-time pickup | Area2D + queue_free on enter | Simple cleanup |
| Line-of-sight | RayCast2D / direct ray | raycast_vision_stack.gd or physics_direct_query.gd |
| Click-to-select | PhysicsPointQueryParameters2D | physics_queries.gd |
| AOE spell / melee volume | ShapeCast2D / shape query | shapecast_aoe.gd (not Area signal lag) |
| Instant-hit weapon | PhysicsRayQueryParameters2D | physics_queries.gd / raycast_hit_prediction.gd |
| Platformer ground / ledge | Ray or ShapeCast down | CharacterBody skill + shapecast_aoe_detection.gd |
| 1000+ projectiles | PhysicsServer2D RIDs | MANDATORY physics_server_swarm.gd |
body_entered once per shape — dedupe with a Set/dict or collision_debouncer.gd.force_raycast_update() / force_shapecast_update()._ready physics queries are false until after a physics frame (await get_tree().physics_frame).CharacterBody2D ships with collision_layer = 0 — Areas won't see it until you set a layer.| Topic | Reference / script |
|-------|-------------------|
| Layer/mask patterns | collision-layers-masks.md |
| Area2D, raycast, shape queries | area2d-and-queries.md |
| Compound RID bodies | compound_body_sync.gd |
| Contact normal debug draw | collision_visual_debugger.gd |
> 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.
CollisionShape2D nodes breaks normals and contacts.move_and_slide / move_and_collide, floor detection, and kinematic movement contracts.RayCast2D vs PhysicsDirectSpaceState2D rays, exclusions, and mid-frame force_raycast_update._integrate_forces / PhysicsDirectBodyState2D instead of fighting the solver in _process.Area2D signal lag is unacceptable._physics_process discipline underpin every pattern here.body_entered / body_exited wiring and debounce patterns need clean signal ownership to avoid spam.move_and_slide feel.PhysicsServer2D swarms or query caches become bottlenecks.Area2D + layer/mask products; damage timing inherits overlap and CCD choices.Take thedivergentai/godot-2d-physics 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.