使用方法
- 复制安装命令,在自己的智能体环境安装前先检查源码包。
- 从原始文档核对所需工具、凭据和支持的宿主。
- 说明输入材料与期望交付物,并对照来源检查输出。
npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill godot-physics开始前需了解
- 安装不包含模型订阅、API 额度或访问文件的权限。
- 仓库星数和安装量反映活跃情况,不等于独立质量或安全测试。
按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。
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. In 3D, projects created with Godot 4.6 or later run Jolt Physics by default; older projects keep GodotPhysics3D unless someone switched them. 2D always uses Godot's own 2D engine.
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
- For 3D, check which engine runs before debugging behavior: Project Settings >
Physics > 3D > Physics Engine ([physics] 3d/physics_engine="Jolt Physics" in project.godot). Projects created in 4.6+ get Jolt written there by default; with no such line (DEFAULT) the engine is GodotPhysics3D. The API is the same, but joints, ray-cast face indices, kinematic contacts, and collision margins behave differently (see Pitfalls).
- 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 (seegodot-2d-movement).Area— detects overlaps and can apply gravity/damping; no solid collision.
Every body needs a CollisionShape (or CollisionPolygon) child.
- 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.
- Detect overlaps with
Areasignals (body_entered,area_entered). - Drive RigidBodies with forces/impulses, or override
_integrate_forcesfor full
control.
- Cast rays with a
RayCast2D/3Dnode (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 = 0b1102. 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/normalPitfalls
- 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
enabledis 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.
Jolt Physics (3D) differences
- `face_index` is always `-1` in
intersect_ray()/RayCast3Dresults under Jolt.
Turn on Project Settings > Physics > Jolt Physics 3D > Queries > Enable Ray Cast Face Index if you need it (it costs roughly 25% more memory for ConcavePolygonShape3D).
- A joint with only one body gets inverted limits after switching engines. Jolt treats
the lone body as node_b with node_a as the world; GodotPhysics3D always treats it as node_a. Assign the body to the slot Jolt expects, or use Physics > Jolt Physics 3D > Joints > World Node for compatibility with an older project.
- Joint soft-limit properties do nothing under Jolt:
bias/damping/impulse_clampon
PinJoint3D; bias/softness/relaxation on HingeJoint3D and ConeTwistJoint3D; angular_* and limit softness/restitution/damping on SliderJoint3D; limit softness/restitution/damping/erp on Generic6DOFJoint3D. Godot warns when they are set to non-default values.
- A frozen kinematic `RigidBody3D` reports no contacts with static or kinematic bodies,
even with max_contacts_reported > 0. Enable Physics > Jolt Physics 3D > Simulation > Generate All Kinematic Contacts if gameplay depends on those contacts.
- Shape `margin` shrinks the shape instead of padding it under Jolt, so sizes stay
true but shape queries can return odd normals on small shapes; the effective margin comes from Physics > Jolt Physics 3D > Collisions > Collision Margin Fraction.
- `Area3D` now fires `body_entered` for `SoftBody3D` under Jolt (GodotPhysics3D never
did). Filter soft bodies out with layers/masks if the old behavior is expected.
- A `WorldBoundaryShape3D` floor sits at the wrong height after upgrading to 4.7 → under
Jolt, 4.7 reads plane.d with Godot's sign convention, the opposite of 4.6; flip the sign of d in projects tuned on 4.6. Jolt also caps the plane's effective size (Physics > Jolt Physics 3D > Limits > World Boundary Shape Size), so bodies far from the origin can fall off an "infinite" floor.
References
- For
_integrate_forces, joints, one-way collision,PhysicsServerdirect access,
shape queries (intersect_shape), and 3D move_and_collide, read references/bodies-and-queries.md.
- Jolt specifics: Godot docs "Using Jolt Physics"
(https://docs.godotengine.org/en/stable/tutorials/physics/using_jolt_physics.html).
Related skills
godot-2d-movement— kinematicCharacterBody2Dcontrollers.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.

