mcpField
P
physics-tuning

physics-tuning

github.com/gamedev-skills开发5.4k7.7k 次安装今天更新
代码仓库

关于 physics-tuning

physics-tuning 是面向游戏开发者的引擎无关物理调校技能,适用于排查抖动、穿透和不稳定运动。内容涵盖固定步长、渲染插值、物体参数、连续碰撞检测与碰撞层。

主要功能

  1. 01固定步长物理模拟
  2. 02渲染插值以减少抖动
  3. 03调节质量、阻力和重力
  4. 04连续碰撞检测与速度限制
  5. 05配置碰撞层和遮罩

适用场景

  1. 01排查低帧率下的运动抖动
  2. 02减少高速物体穿透墙体
  3. 03稳定堆叠物体和关节
  4. 04调整物体的弹性与阻尼

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill physics-tuning

安装后在 Claude Code 中输入/physics-tuning确认已加载。

附带文件references/timestep-and-ccd.md

详细介绍

物理调校

大多数“糟糕的物理效果”并非引擎本身的 Bug,而是固定时间步模拟与可变帧率渲染循环不匹配,或质量、阻力、CCD、层设置未经调校所致。本技能介绍能让物理效果稳定、响应灵敏且与引擎无关的调校项;具体 API 请搭配 godot-physics 或 unity-physics 使用。

适用场景

  • 当运动出现抖动、物体穿墙(隧穿)、堆叠炸开,或移动感觉轻飘、黏滞、迟缓时使用。
  • 当你需要决定哪些操作放在固定(物理)步中、哪些放在渲染帧中,以及如何在两者之间插值时使用。
  • 当你需要调校重力、质量、阻力、恢复系数、求解器迭代次数、休眠状态及碰撞层/遮罩时使用。

**不适用场景:**如需了解某个引擎的具体物理节点/组件和碰撞回调,请使用 godot-physics 或 unity-physics。如需了解移动决策(何时跳跃、AI 转向),请使用 input-systems 和 game-ai。平台跳跃游戏中特有的跳跃手感设置(如土狼时间/跳跃缓冲)属于输入/控制器范畴,请参阅 input-systems 和 platformer 类型指南。

核心工作流

  1. 使用固定时间步运行物理模拟。 以固定频率(例如 50–60 Hz)进行模拟。固定的 dt 能让模拟近似确定且稳定;可变的 dt 会导致积分和碰撞不一致。
  2. 将物理操作放在物理回调中,而不是渲染帧中。在固定步(FixedUpdate/_physics_process)中应用力/速度并读取碰撞,使用该步的 dt。
  3. 在物理刻之间插值渲染。 渲染帧率 ≠ 物理模拟频率,因此应将变换平滑插值至最新的物理状态,或启用引擎的 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/drag 调整手感。
  • 堆叠物体爆开/关节抖动:质量比过于悬殊,或求解器迭代次数过少。请保持适中的质量比并提高迭代次数。
  • 永不静止的刚体会消耗 CPU 并不断抖动。请为静止物体启用休眠,并设置合理的休眠阈值。
  • 单向层设置:A 的遮罩包含 B,但 B 的遮罩不包含 A。检测/碰撞可能需要双方都设置;请检查完整矩阵。
  • dt 出现巨大尖峰(加载卡顿、断点)会导致积分失控。请限制最大物理步长/子步数,避免卡顿时所有物体都被弹飞。

参考资料

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

相关技能

  • godot-physics、unity-physics — 具体的刚体、碰撞体和回调。
  • input-systems — 灵敏的控制、跳跃缓冲、土狼时间。
  • game-ai — 必须与物理步长保持一致的 Agent 移动。
  • platformer、fps-shooter — 手感取决于这些调优的游戏类型。

评论

支持 Markdown