Skip to content
Development
Skill

/godot-physics

Use Godot 4.7 physics bodies and detection in 2D and 3D: RigidBody, StaticBody, Area, and CharacterBody; collision layers vs masks; contact/overlap signals; and raycasts (RayCast nodes and direct space-state queries). Use when configuring collision layers/masks, detecting

From plugin
awesome-gamedev-agent-skills
45567 skills
Install
$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill godot-physics --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/godot-physics

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use Godot 4.7 physics bodies and detection in 2D and 3D: RigidBody, StaticBody, Area, and CharacterBody; collision layers vs masks; contact/overlap signals; and raycasts (RayCast nodes and direct space-state queries). Use when configuring collision layers/masks, detecting

SKILL.md

godot-physics.SKILL.md
name: godot-physics
description: >
  Use Godot 4.7 physics bodies and detection in 2D and 3D: RigidBody, StaticBody,
  Area, and CharacterBody; collision layers vs masks; contact/overlap signals; and
  raycasts (RayCast nodes and direct space-state queries). Use when configuring
  collision layers/masks, detecting overlaps with Area2D/Area3D, applying forces to a
  RigidBody, or casting rays in a Godot project (.tscn with physics bodies).

Godot Physics (4.x, 2D + 3D)

Pick the right physics body, wire up collision layers/masks, detect overlaps, and cast rays. Concepts apply to both 2D and 3D (swap the `2D`/`3D` suffix). Targets **Godot 4.7**.

When to use

  • Use when choosing between body types, setting collision layers/masks so the right

things collide, detecting overlaps (triggers, hurtboxes) with `Area`, applying forces/impulses to a `RigidBody`, or casting rays for line-of-sight/ground checks.

**When *not* to use:** kinematic character controllers (`move_and_slide`) → `godot-2d-movement`; tile collision setup → `godot-tilemap`; tuning the *feel* of physics (timestep, mass, jitter) → `physics-tuning`.

Core workflow

1. **Choose the body type:**

  • `StaticBody` — never moves (floors, walls). Collides, no simulation.
  • `RigidBody` — fully simulated (gravity, forces, bouncing). Don't set its

`position` directly; apply forces/impulses or set `linear_velocity`.

  • `CharacterBody` — script-driven kinematic (see `godot-2d-movement`).
  • `Area` — detects overlaps and can apply gravity/damping; no solid collision.

Every body needs a `CollisionShape` (or `CollisionPolygon`) child. 2. **Configure layers and masks.** A body is *on* its **layers** and *scans for* its **masks**. Two bodies interact only if one's layer is in the other's mask. Name layers in Project Settings > Layer Names for clarity. 3. **Detect overlaps** with `Area` signals (`body_entered`, `area_entered`). 4. **Drive RigidBodies with forces/impulses**, or override `_integrate_forces` for full control. 5. **Cast rays** with a `RayCast2D/3D` node (polled each frame) or a one-shot space-state query from code.

Patterns

1. Collision layers vs masks (set from code)

# Player is on layer 1, scans layers 2 (walls) and 3 (enemies).
func _ready() -> void:
    set_collision_layer_value(1, true)    # I am on layer 1
    set_collision_mask_value(2, true)     # I collide with things on layer 2
    set_collision_mask_value(3, true)     # ...and layer 3
    # Bit-field forms also exist: collision_layer = 1; collision_mask = 0b110

2. Area2D as a trigger / hurtbox

extends Area2D                            # e.g. a damage zone

func _ready() -> void:
    body_entered.connect(_on_body_entered)
    area_entered.connect(_on_area_entered)

func _on_body_entered(body: Node2D) -> void:
    if body.has_method("take_damage"):
        body.take_damage(10)

func _on_area_entered(area: Area2D) -> void:
    print("Overlapped area: ", area.name)

3. Applying force and impulse to a RigidBody3D

extends RigidBody3D

func push(direction: Vector3) -> void:
    apply_central_impulse(direction * 8.0)     # instantaneous velocity change

func _physics_process(_delta: float) -> void:
    apply_central_force(Vector3.FORWARD * 4.0) # continuous force (per tick)
    # Never set `position` on a RigidBody to move it; use forces/impulses or
    # set linear_velocity. Use freeze=true if you must hold it in place.

4. Raycast two ways

# A) RayCast2D node: enable it, then poll after physics has updated.
@onready var ray: RayCast2D = $RayCast2D    # set target_position in the editor

func _physics_process(_delta: float) -> void:
    if ray.is_colliding():
        var hit := ray.get_collider()
        var point := ray.get_collision_point()

# B) One-shot query from code (no node needed).
func ground_under(global_from: Vector2) -> Dictionary:
    var space := get_world_2d().direct_space_state
    var query := PhysicsRayQueryParameters2D.create(global_from, global_from + Vector2(0, 64))
    query.collision_mask = 1                 # only layer 1
    return space.intersect_ray(query)        # {} if nothing hit, else collider/position/normal

Pitfalls

  • **Layer vs mask confusion** is the #1 bug. Layer = "what I am"; mask = "what I look

for". For A to detect B, B's layer must be in A's mask. Detection can be one-directional.

  • **Moving a RigidBody by `position`** fights the solver and causes tunneling/jitter.

Use impulses/forces, set `linear_velocity`, or `freeze` it. To teleport, set position and zero the velocities inside `_integrate_forces`.

  • **`Area` doesn't fire** when neither monitoring nor monitorable is set, or layers/masks

don't overlap. `monitoring` must be on for the Area to detect; `monitorable` lets others detect it.

  • **RayCast2D/3D read stale or no data** if `enabled` is false, or if you read it before

physics updated — read in `_physics_process`, and call `force_raycast_update()` after moving it within the same tick.

  • **Forgetting a `CollisionShape`** (or leaving it empty) means the body never collides.
  • **Fast objects tunnel** through thin walls; enable **continuous CD** on the RigidBody

(`continuous_cd`) or use a raycast-based check.

  • **`intersect_ray` excludes its own body?** Pass `query.exclude = [self.get_rid()]` (an

`Array[RID]`, not an array of nodes) to skip self-hits.

References

  • For `_integrate_forces`, joints, one-way collision, `PhysicsServer` direct access,

shape queries (`intersect_shape`), and 3D `move_and_collide`, read `references/bodies-and-queries.md`.

Related skills

  • `godot-2d-movement` — kinematic `CharacterBody2D` controllers.
  • `godot-tilemap` — tile collision shapes and their layers.
  • `physics-tuning` — engine-agnostic feel: timestep, mass, drag, CCD.
  • `godot-3d-essentials` — 3D scene setup these bodies live in.
Read more
Ships withawesome-gamedev-agent-skills

<img src="docs/assets/banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.

Get the whole plugin
Stats
458
Stars
36
Forks
Active
Maintenance
Python
Language
Apache-2.0
License
1d ago
Last commit
1mo ago
Created

Repo: gamedev-skills/awesome-gamedev-agent-skills