我在一个非常简单的XNA 4测试游戏中使用Farseer Physics Engine 3.3.1。 (注意:我也在标记这个Box2D,因为Farseer是Box2D的直接端口,我很乐意接受解决这个问题的Box2D答案。)
在这个游戏中,我创造了两个身体。第一个正文是使用BodyFactory.CreateCircle
和BodyType.Dynamic
创建的。可以使用键盘(设置Body.LinearVelocity)移动此主体。第二个正文是使用BodyFactory.CreateRectangle
和BodyType.Static
创建的。这个身体是静止的,永远不会移动。
然后我使用此代码计算两个物体碰撞时的碰撞力:
staticBody.FixtureList[0].AfterCollision += new AfterCollisionEventHandler(AfterCollision);
protected void AfterCollision(Fixture fixtureA, Fixture fixtureB, Contact contact)
{
float maxImpulse = 0f;
for (int i = 0; i < contact.Manifold.PointCount; i++)
maxImpulse = Math.Max(maxImpulse, contact.Manifold.Points[i].NormalImpulse);
// maxImpulse should contain the force of the collision
}
如果这两个主体都设置为IgnoreCCD=true
,则此代码非常有用。我可以100%可靠地计算它们之间的碰撞力。完美。
但问题在于:如果我将主体设置为IgnoreCCD = false,那么代码就变得非常难以预测。可靠地调用AfterCollision,但由于某种原因,NormalImpulse 0 大约75%的时间,因此只有大约四分之一的碰撞被登记。更糟糕的是,由于完全随机的原因,NormalImpulse似乎为零。动态体可以以相同的方式在几乎完全的情况下连续10次与静态体碰撞,并且只有2或3个命中将以大于零的NormalImpulse记录。在两个物体上设置IgnoreCCD=true
可立即解决问题,但随后我将失去连续物理检测。
为什么会发生这种情况,我该如何解决?
这是一个简单的XNA 4解决方案的链接,它演示了这个问题: http://www.mediafire.com/?a1w242q9sna54j4
答案 0 :(得分:0)
虽然我没有试过这个,所以我无法给出明确的答案,我认为这些来自Box2D源代码的摘录可能是相关的:
/// This lets you inspect a contact after the solver is finished. This is useful
/// for inspecting impulses.
/// Note: the contact manifold does not include time of impact impulses, which can be
/// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly
/// in a separate data structure.
/// Note: this is only called for contacts that are touching, solid, and awake.
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{
B2_NOT_USED(contact);
B2_NOT_USED(impulse);
}
这可能是AfterContact所依据的,并且它说的是用于将身体推回到CCD的原始第一接触位置(冲击冲击时间)的所有脉冲的中间结果是基本上不适合你:(