2D圆形碰撞Resolution问题求助:求实现真实刚体碰撞的正确方案
2D刚体碰撞Resolution的正确实现方案
先说说你之前代码的问题:
- 第一个代码用持续加力处理碰撞,刚体碰撞是瞬间冲量作用,不是持续受力;而且没处理物体重叠,导致每帧都触发受力,所以物体像弹簧一样来回晃。
- 第二个代码只改了速度,但没解决重叠问题,物体一直卡在一起,每帧都重复碰撞检测和速度修改,自然会卡顿;另外冲量公式没考虑弹性(恢复系数),质量项的计算也有问题。
刚体碰撞的正确处理需要分两步:先把重叠的物体分开(位置修正),再计算碰撞后的速度变化(冲量),下面是具体实现和原理:
第一步:位置分离(解决物体重叠)
碰撞检测得到的depth是两个物体的重叠深度,必须沿碰撞法线方向把它们分开,不然下一帧还会触发碰撞。按质量反比分配位移更真实——轻的物体被推开更多,重的物体几乎不动:
public static void FixOverlap(RigidBody a, RigidBody b, Vec2 collisionNormal, float depth) { // 计算位移比例,避免质量为0的静态物体出问题 float totalMass = a.Mass + b.Mass; float aMoveRatio = b.Mass / totalMass; float bMoveRatio = a.Mass / totalMass; // 沿法线方向修正位置,消除重叠 Vec2 aMove = collisionNormal * depth * aMoveRatio; Vec2 bMove = collisionNormal * depth * -bMoveRatio; a.Position += aMove; b.Position += bMove; }
第二步:速度冲量计算(模拟刚体碰撞反弹)
基于动量守恒和恢复系数(控制弹性)计算瞬间冲量,直接修改速度,这才是刚体碰撞的正确方式:
- 恢复系数
e:0是完全非弹性碰撞(粘在一起),1是完全弹性碰撞(无能量损失),一般设0.8左右接近真实刚体 - 先判断物体是否已经在分离,避免重复处理
- 冲量公式是从动量守恒和碰撞定律推导来的,核心是修正法线方向的相对速度
public static void UpdateCollisionVelocity(RigidBody a, RigidBody b, Vec2 collisionNormal, float restitution = 0.8f) { // 计算两个物体的相对速度在法线方向的分量 Vec2 relVelocity = b.Velocity - a.Velocity; float relVelDotNormal = relVelocity.Dot(collisionNormal); // 如果物体已经在往分离的方向动,不用处理 if (relVelDotNormal > 0) return; // 计算冲量大小 float impulseMagnitude = -(1 + restitution) * relVelDotNormal; impulseMagnitude /= (1 / a.Mass) + (1 / b.Mass); // 把冲量应用到两个物体的速度上 Vec2 impulse = collisionNormal * impulseMagnitude; a.Velocity -= impulse / a.Mass; b.Velocity += impulse / b.Mass; }
完整的碰撞处理函数
把两步结合起来,就是完整的碰撞Resolution逻辑:
public static void OnCollision(RigidBody a, RigidBody b, float depth) { // 计算碰撞法线(从a指向b,必须归一化) Vec2 collisionNormal = b.Position - a.Position; collisionNormal = VectorMath.Normalize(collisionNormal); // 先解决重叠问题 FixOverlap(a, b, collisionNormal, depth); // 再处理速度变化 UpdateCollisionVelocity(a, b, collisionNormal); }
核心原理说明
- 位置分离是基础:离散碰撞检测的特性决定了,当你检测到碰撞时,物体已经重叠了。如果不分离,会反复触发碰撞处理,导致卡顿或异常运动。按质量反比分配位移,符合现实中“重物体难推动”的规律。
- 冲量替代持续力:刚体碰撞是瞬间作用,冲量是力×时间的累积,直接修改速度比每帧加力更符合刚体的“硬”特性,不会出现弹簧一样的软效果。
- 恢复系数控制弹性:不同材质的物体碰撞弹性不同,这个参数能让你调整碰撞的真实感,比如橡胶球设0.9,石头设0.5。
- 分离判断避免无效处理:如果碰撞后物体已经在分开,就不用再修改速度,避免重复操作导致的异常。
内容的提问来源于stack exchange,提问作者Avi_H
相关产品推荐
相关产品推荐

