0

我在一个非常简单的 XNA 4 测试游戏中使用 Farseer Physics Engine 3.3.1。(注意:我也标记了这个 Box2D,因为 Farseer 是 Box2D 的直接端口,我很乐意接受解决这个问题的 Box2D 答案。)

在这个游戏中,我创造了两个身体。第一个主体是使用BodyFactory.CreateCircleand创建的BodyType.Dynamic。可以使用键盘(设置 Body.LinearVelocity)来移动这个身体。第二个主体是使用BodyFactory.CreateRectangleand创建的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 大约有 75% 的时间为0,因此仅记录了大约四分之一的碰撞。更糟糕的是,由于完全随机的原因,NormalImpulse 似乎为零。动态物体可以以几乎完全相同的方式连续 10 次与静态物体碰撞,并且只有 2 或 3 次碰撞会记录到大于零的 NormalImpulse。在两个身体上设置IgnoreCCD=true立即解决了问题,但随后我失去了连续的物理检测。

为什么会发生这种情况,我该如何解决?


这是一个简单的 XNA 4 解决方案的链接,该解决方案演示了这个问题的实际效果: http ://www.mediafire.com/?a1w242q9sna54j4

4

1 回答 1

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 的原始第一个接触位置的所有脉冲的中间结果(冲击脉冲时间)对你来说基本上是不可用的:(

于 2012-12-15T05:13:49.877 回答