乌啦呀哈呀哈乌啦!

欢迎光临,这里是喵pass的个人博客,希望有能帮到你的地方

0%

穿透问题和碰撞检测

游戏中的“穿透”通常有两种不同的问题:
物体在一次更新中直接越过障碍物,碰撞根本没有被检测到;或者碰撞已经被检测到,但物体仍然陷进了障碍物,甚至被挤到另一侧。

物体高速穿墙

物理引擎通常按固定时间间隔更新,而不是在每一个真实时间点都计算碰撞。

采用离散碰撞检测时,可以将问题理解为:物理引擎检查更新时刻的碰撞形状,却没有充分检查两次更新之间经过的路径。

上一次物理更新 下一次物理更新
● ──────────│墙│────────── ●
检查时没重叠 检查时也没重叠

虽然运动路径经过墙,但两个检查时刻都没有重叠,于是碰撞可能被漏掉。这通常叫 Tunneling,隧穿。

真正需要关注的是相对运动速度。两个物体迎面运动时,即使各自速度不算特别高,相对速度也可能很高。
旋转同样可能造成问题:长杆快速旋转时,杆的末端可以在一个物理步内跨过很远的距离。

一个实用的判断思路是:

当“每个物理步的相对位移”接近或超过“障碍物和运动物体在运动方向上的有效尺寸”时,离散检测漏碰撞的风险会明显增大。
这只是风险判断,不是严格的安全保证。斜向移动、旋转、形状和接触位置都会影响结果。

物体陷进障碍物

这属于另一个问题:碰撞求解不够及时、不够准确,或者运动方式绕过了求解过程。

多数实时物理引擎允许出现少量重叠,然后通过接触约束、速度修正和位置修正,让物体逐渐分离。因此,轻微的嵌入不一定代表检测失效。

严重嵌入通常与这些因素有关:

  • 外力或速度太大,接触约束来不及阻止运动。
  • 堆叠、关节或多处接触很复杂,求解迭代次数不足。
  • 相互接触的动态物体质量差距很大,求解更难稳定。
  • 脚本持续强行设置位置,把物体反复推入墙中。
  • 物体生成时就与场景重叠。
  • 碰撞体尺寸、形状或缩放不合理。

例如,角色已经撞到墙,但脚本每帧仍然执行:

1
transform.position += direction * speed * Time.deltaTime;

这段代码直接改变位置,并没有要求物理系统先判断这一步能否移动。即使检测到了碰撞,下一帧脚本仍可能再次把角色推进墙内。

解决方案

方案 原理 适用场景 局限或代价
连续碰撞检测 CCD 检查运动过程中的碰撞,或预测接触 高速刚体、弹丸 增加计算开销,具体模式对旋转等情况支持不同
缩短物理步长 提高物理更新频率,减小每步位移 整体物理模拟 CPU 开销增加,极高速物体仍可能穿透
增加子步 将一次运动拆成多次,每次都检测碰撞 快速角色、机关、复杂运动 子步越多,开销越大
射线检测 检查当前位置到预计下一位置的线段 小子弹、瞬时射击 射线没有厚度,不适合直接代表大物体
形状扫掠 用球、胶囊或盒子检查运动路径 有体积的弹丸、角色 需要处理初始重叠、多次碰撞和旋转
限制速度或单步位移 避免一次跨过障碍物 普通角色、箱子、慢速机关 可能改变运动效果
加厚、简化碰撞体 增加可检测的接触范围,改善接触稳定性 薄墙、复杂场景模型 可能出现视觉模型与碰撞边界不一致
移动前检测并截断位移 发现障碍物后,只移动到接触位置附近 自定义角色、运动学对象 需要实现滑动、台阶和拐角处理
重叠检测与位置恢复 检测已有嵌入,计算分离方向并修正位置 生成、传送、平台挤压 属于事后修正,处理不好会抖动或弹出
调整碰撞求解参数 提高接触约束的求解精度 堆叠下陷、关节拉伸、持续嵌入 无法解决根本没检测到的碰撞
改变对象实现方式 用命中查询或逻辑轨迹替代高速实体 枪械、飞行弹丸 需要自行实现飞行、命中和表现逻辑

这里有几个容易混淆的地方。

射线和形状扫掠虽然可以替代引擎内置 CCD,但沿运动路径检测碰撞,本身也属于连续检测的思路。
如果你想找原理上不同于 CCD 的办法,主要是缩短步长、增加离散子步、限制速度、调整碰撞体,以及重叠修正。

增加子步必须包含检测。
例如把一次移动拆成十次,每次都查询碰撞才有意义;只在循环里设置十次位置,物理引擎未必会在中间进行检测。

提高求解迭代次数主要解决“碰到了却挡不稳”。
它适合箱子堆叠、复杂接触等情况,不能解决子弹直接跳过薄墙造成的漏检测。

实际选择可以按对象来定:

  • 小子弹:检查前后位置之间的射线;需要飞行时间时,逐步计算轨迹并查询。
  • 火球、炮弹等有体积的弹丸:使用球形扫掠,或者适合的 CCD。
  • 玩家角色:移动前做胶囊查询,截断位移,再处理沿墙滑动和重叠恢复。
  • 动态箱子:检查移动方式和碰撞体,再按需要调整步长、CCD 和求解参数。
  • 快速挥剑、旋转刀片:采样旋转轨迹或检测扫掠体积,单纯检查中心移动路径不够。
  • 传送后卡进墙里:先验证目标位置,再做必要的重叠恢复。

通常会组合使用。例如角色采用 移动前形状查询+沿墙滑动+重叠恢复;高速弹丸采用 轨迹查询+首次命中处理。