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

physics-tuning

@admin/physics-tuning

调整游戏物理手感与稳定性,处理时间步长、插值、质量和阻力,修复抖动、碰撞穿透及碰撞层问题。

admin 热度 451v0.0.1

物理调优

大多数“糟糕的物理”不是引擎中的错误——而是固定时间步长模拟可变速率渲染循环之间的不匹配,或者质量/阻力/CCD/层设置未调优。本技能涵盖使物理稳定且响应灵敏的与引擎无关的调节项;将其与 godot-physicsunity-physics 搭配使用,以获取具体 API。

何时使用

  • 当运动抖动、物体穿墙(穿模)、堆叠爆炸,或移动感觉漂浮/粘滞/卡顿时使用。
  • 用于决定哪些内容放在固定(物理)步长中,哪些放在渲染帧中,以及如何在它们之间插值。
  • 用于调优重力、质量、阻力、恢复系数、求解器迭代、休眠,以及碰撞层/遮罩。

**何时*不*使用:** 对于引擎的具体物理节点/组件和碰撞回调,请使用 godot-physicsunity-physics。对于*移动决策*(何时跳跃、AI 转向),请使用 input-systemsgame-ai。对于平台跳跃跳跃手感细节,例如土狼时间/跳跃缓冲,这属于输入/控制器领域——参见 input-systemsplatformer 类型。

核心工作流

  1. 以固定时间步长运行物理。 以恒定速率模拟(例如 50–60 Hz)。固定 dt 使模拟大致确定且稳定;可变 dt 会使积分和碰撞不一致。
  2. 将物理工作放在物理回调中,而不是渲染帧中。在固定步长(FixedUpdate / _physics_process)中应用力/速度并读取碰撞,使用该步长的 dt
  3. 在物理 tick 之间插值渲染。 渲染帧率 ≠ 物理速率,因此应将变换平滑插值到最新物理状态,或启用引擎的 Rigidbody 插值,以消除可见卡顿。
  4. 调优刚体,而不是场景。 设置质量以获得相对重量,设置阻力以获得阻尼,设置每个对象的重力缩放,并通过材质设置恢复系数/摩擦。
  5. 使用 CCD 阻止穿模,针对小/快刚体;限制最大速度。
  6. 稳定堆叠/关节,通过更多求解器迭代、合理的质量比,以及为静止刚体启用休眠。
  7. 通过手感和压力测试验证。 以低和高帧率游玩;向薄墙投掷快速物体;堆叠并推挤刚体。报告你观察到的现象。

模式

1. 固定时间步长用于模拟,渲染插值用于平滑

# Physics callback: runs at the FIXED rate. Use its dt for all integration.
func _physics_process(dt):                  # Unity: void FixedUpdate()
    velocity += gravity * dt                # integrate with the FIXED dt
    move_and_slide()                        # engine resolves collisions this step
    _prev_pos = _curr_pos; _curr_pos = global_position   # record for interpolation

# Render frame: runs as fast as the display. Interpolate between physics states.
func _process(_frame_dt):                   # Unity: void Update()
    var alpha = Engine.get_physics_interpolation_fraction()  # 0..1 within the tick
    visual.global_position = _prev_pos.lerp(_curr_pos, alpha)
# RIGHT: integrate in the fixed step, render via interpolation.
# WRONG: applying forces in _process/Update with frame dt — speed and collisions
# then depend on frame rate and jitter under load.

大多数引擎已为你提供此功能(Godot physics_interpolation/Rigidbody 插值;Unity Rigidbody.interpolation = Interpolate)。优先使用内置功能,而不是手写实现。

2. 阻止穿模:CCD + 速度上限

# Fast, small bodies skip past thin colliders between ticks. Two fixes:
body.continuous_cd = true            # RigidBody3D bool (RigidBody2D: CCD_MODE_* enum). Unity: rb.collisionDetectionMode = Continuous
# Cap velocity so a single step can't move more than ~one collider thickness.
const MAX_SPEED := 40.0
if velocity.length() > MAX_SPEED:
    velocity = velocity.normalized() * MAX_SPEED
# Rule of thumb: max_distance_per_step (= speed / physics_hz) should be < the
# thinnest wall. Raise physics_hz or enable CCD when that fails.

3. 刚体调优:质量、阻力、重力缩放、材质

# Mass is RELATIVE weight in collisions; it does NOT change fall speed (gravity
# accelerates all masses equally). Use drag and gravity_scale to shape feel.
body.mass = 2.0                      # heavier pushes lighter in collisions
body.linear_damp = 0.5               # air drag: higher = stops sooner (Unity: drag)
body.gravity_scale = 1.5             # per-object gravity multiplier (snappier fall)
# Bounce/slide come from the physics material, not code:
material.bounce = 0.2                # restitution 0..1 (Unity: bounciness)
material.friction = 0.8              # surface grip

4. 碰撞层与遮罩(谁与谁碰撞)

# A body is ON its layer(s) and SCANS the layers in its mask. Both directions of a
# pair must be configured for them to interact.
player.collision_layer = LAYER_PLAYER
player.collision_mask  = LAYER_WORLD | LAYER_ENEMY     # player detects world+enemies
pickup.collision_layer = LAYER_PICKUP
pickup.collision_mask  = LAYER_PLAYER                  # pickup only reacts to player
# Unity equivalent: assign GameObject layers and edit the Physics collision matrix
# (or Physics.IgnoreLayerCollision). Keep a named layer constant table, not magic numbers.

陷阱

  • 在渲染帧中应用力/移动Update/_process)会使行为依赖帧率——更快的 PC 运行更快,碰撞变得不稳定。在固定步长中进行模拟。
  • 可见抖动即使使用固定步长,通常也意味着没有渲染插值:物理速率和显示速率彼此冲突。启用插值。
  • 穿模穿过薄墙:离散碰撞会错过快速移动者。启用 CCD,限制速度,加厚墙壁,或提高物理速率。
  • 期望更重的物体下落更快。 重力是加速度;质量影响碰撞响应,而不是下落速度。使用 gravity_scale/阻力来获得手感。
  • 堆叠爆炸 / 关节抖动:质量比过于极端,或求解器迭代次数太少。保持质量比适度,并提高迭代次数。
  • 永不停止的刚体会消耗 CPU 并抽搐。为静止物体启用休眠和合理的休眠阈值。
  • 单向层设置:A 的遮罩包含 B,但 B 的遮罩不包含 A。检测/碰撞可能需要双方;验证完整矩阵。
  • 巨大的 dt 尖峰(加载卡顿、断点)会破坏积分。限制最大物理步长/子步计数,以免停顿导致一切被弹飞。

参考资料

  • references/timestep-and-ccd.md — 固定时间步长累加器循环、插值数学、子步进、CCD 模式、求解器/迭代调优、休眠,以及稳定性检查清单。

相关技能

  • godot-physics, unity-physics — 具体刚体、碰撞体和回调。
  • input-systems — 响应式控制、跳跃缓冲、土狼时间。
  • game-ai — 必须与物理步长一致的代理移动。
  • platformer, fps-shooter — 手感依赖此调优的类型。
qianwen skills install @admin/physics-tuning