我正在尝试制作一个2D游戏引擎,但我似乎无法让碰撞一直工作(通常情况下会遇到困难或相互传递)。如果没有太多进入代码,这里是我更新的顺序。
碰撞脉冲在此函数中计算:
private static void CollisionImpulse(PhysicsEntity a, PhysicsEntity b)
{
var relative = b.Velocity.Vector - a.Velocity.Vector;
var normal = Vector2.Normalize(relative);
var e = Math.Min(a.Material.Elasticity, b.Material.Elasticity);
var j = (-(1 + e) * Vector2.Dot(relative, normal)) /
(Vector2.Dot(normal, normal) * (a.InverseMass + b.InverseMass));
if (double.IsNaN(j)) return;
var velocityA = normal * (float) (j / a.Mass);
var velocityB = normal * (float) (j / b.Mass);
a.Velocity.X -= velocityA.X;
a.Velocity.Y -= velocityA.Y;
if (!b.Movable) return;
b.Velocity.X += velocityB.X;
b.Velocity.Y += velocityB.Y;
b.Position = b.OldPosition;
}
这是检查碰撞的函数:
public override void Update()
{
foreach (var entity in Universe.PhysicsEntities)
{
if (entity.Equals(this) || entity.Collided) continue;
CollisionResolution.ResolveCollision(this, entity);
if (!Collided) continue;
Position = OldPosition;
break;
}
}
我一直试图调整代码几天,但我无法弄清楚出了什么问题。我希望一些新鲜的眼睛可以解释我的困境。
答案 0 :(得分:2)
第3步存在一个基本问题“如果实体与某些东西发生碰撞,它会移动到旧位置......” - 因为您现在再次移动此实体,您需要重新运行碰撞检测此实体的所有先前实体,否则您可能会导致重叠。
E.g。如果你有3个球池(A,B,C),你将所有3个移动到他们想要的新位置A',B',C'(在你的步骤2中)。现在步骤3你检查A'B'和A'C'不会碰撞,但他们不会碰撞,但是你检查B'C'然后他们碰撞了,所以在你的解决方案中你移动B',C '回到B,C - 但现在技术上你可能已经移动了B和/或C,所以现在它与A相交。
要使第3步工作,您需要:
1)确保在开始时没有任何对象重叠,并且当您在步骤3中检测到碰撞时,或者(a)重新运行我们之前说过的每个先前没有与这些对象发生碰撞的对象的碰撞,或者继续重新运行整个步骤3,直到最后一个循环没有重置任何对象。如果您拥有大量对象并且它们都开始相互重置,这可能会变得昂贵。
或:
2)不是每次将物体重置到最后一帧的“安全”位置,合力(因此加速度,而不是速度)与物体相互穿透的程度有关。这在3D物理引擎中很常见,如果它们穿透过多会导致物体爆炸。
另请注意,如果您将对象移动到1帧(例如,超过其大小的一半),则可能会在没有碰撞重叠检测触发的情况下通过另一个对象。这通常被称为穿纸问题