返回技能市场
开发运维 安全

godot-physics

@admin/godot-physics

配置 Godot 二维与三维物理体、碰撞层和遮罩,处理刚体受力、区域重叠检测及射线查询。

admin 热度 328v0.0.1

Godot 物理(4.x、2D + 3D)

选择正确的物理体,设置碰撞层/掩码,检测重叠,并投射 射线。概念同时适用于 2D 和 3D(交换 2D/3D 后缀)。目标 版本为 Godot 4.7

何时使用

  • 在以下情况使用:在体类型之间选择、设置碰撞层/掩码以便正确的
  • 对象发生碰撞、使用 Area 检测重叠(触发器、伤害框)、对 RigidBody 施加力/冲量,或投射射线以进行视线/地面检查。

**何时*不*使用:** 运动学角色控制器(move_and_slide)→ godot-2d-movement;瓦片碰撞设置 → godot-tilemap;调整物理的 *手感*(时间步长、质量、抖动)→ physics-tuning

核心工作流

  1. 选择体类型:
  • StaticBody — 从不移动(地板、墙壁)。会发生碰撞,但不模拟。
  • RigidBody — 完全模拟(重力、力、弹跳)。不要直接设置其
  • position;施加力/冲量或设置 linear_velocity

  • CharacterBody — 由脚本驱动的运动学体(参见 godot-2d-movement)。
  • Area — 检测重叠,并可应用重力/阻尼;没有实体碰撞。
  • 每个体都需要一个 CollisionShape(或 CollisionPolygon)子节点。

  1. 配置层与掩码。 一个体*位于*其 上,并*扫描*其 掩码。只有当一个体的层位于另一个体的掩码中时,两个体才会交互。在 Project Settings > Layer Names 中命名层,以便清晰。
  2. 使用 Area 信号检测重叠body_enteredarea_entered)。
  3. 通过力/冲量驱动 RigidBody,或重写 _integrate_forces 以获得完全
  4. 控制。

  5. 使用 RayCast2D/3D 节点投射射线(每帧轮询),或通过代码进行一次性
  6. 空间状态查询。

模式

1. 碰撞层与掩码(通过代码设置)

# 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 用作触发器 / 伤害框

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. 对 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. 两种射线检测方式

# 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

陷阱

  • 层与掩码混淆是 #1 错误。层 = “我是什么”;掩码 = “我寻找什么”。
  • 要让 A 检测到 B,B 的层必须位于 A 的掩码中。检测可以是单向的。

  • 通过 position 移动 RigidBody 会与求解器对抗,并导致穿隧/抖动。
  • 使用冲量/力、设置 linear_velocity,或冻结它。要传送,请在 _integrate_forces 内设置位置并使速度归零。

  • Area 不会触发,当 monitoring 和 monitorable 都未设置,或层/掩码
  • 不重叠时。monitoring 必须开启,Area 才能检测;monitorable 让其他 对象检测到它。

  • RayCast2D/3D 读取过期或无数据,如果 enabled 为 false,或在物理
  • 更新前读取它 — 请在 _physics_process 中读取,并在同一帧移动它之后 调用 force_raycast_update()

  • 忘记 CollisionShape(或留空)意味着体永远不会碰撞。
  • 快速物体会穿隧,穿过薄墙;在 RigidBody 上启用 continuous CD
  • continuous_cd),或使用基于射线检测的检查。

  • intersect_ray 会排除自身体吗? 传递 query.exclude = [self.get_rid()]
  • (一个 Array[RID],而不是节点数组)以跳过自身命中。

参考

  • 有关 _integrate_forces、关节、单向碰撞、直接访问 PhysicsServer
  • 形状查询(intersect_shape)以及 3D move_and_collide,请阅读 references/bodies-and-queries.md

相关技能

  • godot-2d-movement — 运动学 CharacterBody2D 控制器。
  • godot-tilemap — 瓦片碰撞形状及其层。
  • physics-tuning — 与引擎无关的手感:时间步长、质量、阻力、CCD。
  • godot-3d-essentials — 这些体所在的 3D 场景设置。
qianwen skills install @admin/godot-physics