MOT 运动学与碰撞检测
概述
游戏帧循环中的物理模拟需要与业务状态管理区别对待:业务状态追求 immutable + 可追踪,物理状态追求低分配 + 稳定帧时间。MOT 的球体位置用 mutate-in-place 更新,避免 60fps 循环中每帧创建短命对象触发 GC。
工作方式
帧率无关运动
position += velocity * dt。dt 来自真实帧间隔,而非固定值。这让物理在 60Hz 和 120Hz 上表现一致。
dt 需要钳位(Math.min(dt, MAX_DT_MS))防止切后台后球体瞬移。不做钳位可能触发 spiral of death:一帧太慢 → 下一帧补更多时间 → 更慢。
边界反弹
位置钳位 + 速度方向修正必须同帧完成。只反转速度不钳位 → 球粘在墙外;只钳位不反转 → 球继续冲出。
弹性碰撞
两圆重叠时:
- 沿连心线法线各推开一半 overlap(位置分离,防粘连)
- 速度投影到法线/切线,法向速度互换、切向不变(等质量弹性碰撞)
O(n²) 逐对检测对 8 球足够,比空间分区更直观。
为什么 mutate-in-place
球体坐标只有画布消费,不需要 React 响应式订阅。immutable update 每帧创建 N 个新对象 → GC 暂停正好在动画路径上。mutable ref 避免了这个问题,同时仍然可以用普通函数调用 + 断言来测试。
参见
- Skia 帧驱动动画 — 渲染路径选择
- 项目文档:
docs/learning/21-mot-kinematics.md