【问题标题】:Box2d As3 contact listener problemBox2d As3 接触监听问题
【发布时间】:2011-06-15 14:32:30
【问题描述】:

我遇到了 box2d as3 b2ContactListener 类的问题。我有一个名为 ContactListener 的类,它扩展了 b2ContactListener 并覆盖了 PostSolve 方法。 PostSolve 采用 2 个参数,contact 保存有关 2 个有联系的对象的信息,以及 impulsion 保存有关联系的信息。我使用脉冲参数来决定 2 个物体的撞击强度,然后我相应地施加伤害。

问题来了: 如果我做任何圆形的东西,让它在我作为地面的静止物体上慢慢滚动,然后将一个相当大的物体放在地面上的任何地方,运动中的圆圈会接触到一个重复的冲动,这就是大的只是滚动。它会导致滚动的圆形物体在不应该的时候破裂。

它几乎就像是在晃动静止的身体,对数百米外的物体造成巨大的伤害,但它只影响圆圈。

任何人都可以了解情况吗?这是一个已知的问题?解决方法?

我使用的是 Box2DAs3 2.1a 版。

更新:一旦身体进入这种施加大量伤害的奇怪状态,任何接触到它的圆圈都会产生大量的大脉冲。一旦非圆形的东西与身体接触,它就不再有问题了。此外,这个问题不仅存在于静态对象上,还存在于动态和运动学上。

更新:我已进一步缩小问题范围。当一个大物体的平坦边缘撞击我的地面物体时,接触听众会吓坏并施加质量脉冲。任何醒着并接触地面的对象,不仅仅是圆圈,都会得到大量的 PostSolve 方法调用。我尝试将一个大小为 11 像素 x 11 像素的盒子放到地上,同时一个圆圈在地上滚动。该错误没有发生。但是,如果框是 12 x 12,则确实会发生错误。此外,如果我将大小为 12 的框旋转 12 到 0.1 度,则不会发生错误。需要有足够大的接触区域才能复制。盒子的密度也不会影响任何事情。此外,如果该框是一个宽度为 10 且高度为 100 的矩形,并且该错误将重现。几乎就像是对象的大小导致了错误,可能不是接触区域的大小。

更新:这是我发布的 Box2D 论坛帖子的链接,其中包含带有源代码的示例 swf。

Link

【问题讨论】:

  • 我对 box2d 一无所知,但这实际上具有一定的物理意义,如果它影响静止的圆圈和滚动的圆圈。
  • 睡圈,睡着和醒着的多边形都不受它的影响。
  • 令人着迷!这听起来像是 box2d 中的一个错误,我认为不会有一个干净的解决方法。
  • 你能发布一个链接到你所描述的内容吗?
  • @Zevan 我添加了一个示例链接

标签: flash actionscript-3 physics box2d collision


【解决方案1】:

哇。所以我终于找到了问题所在。

经过数小时试图通过在 ContactListener 中做一些花哨的事情来确定是否有解决方法后,我决定查看并查看调用 PostSolve 方法的位置。它来自一个名为 b2Island 的类,它来自该类中的 Report 函数。乍一看,我很容易发现了这个问题。她是函数:

private static var s_impulse:b2ContactImpulse = new b2ContactImpulse();
public function Report(constraints:Vector.<b2ContactConstraint>) : void
{
    if (m_listener == null)
    {
        return;
    }

    for (var i:int = 0; i < m_contactCount; ++i)
    {
        var c:b2Contact = m_contacts[i];
        var cc:b2ContactConstraint = constraints[ i ];

        for (var j:int = 0; j < cc.pointCount; ++j)
        {
            s_impulse.normalImpulses[j] = cc.points[j].normalImpulse;
            s_impulse.tangentImpulses[j] = cc.points[j].tangentImpulse;
        }
        m_listener.PostSolve(c, s_impulse);
    }
}

所以是的,显然 s_impulse 变量是静态的,因此对于 b2Island 类的每个实例(如果有多个实例)它都是相同的,而且它在任何时候都不会被重置。所有对 s_impulse 变量的引用都可以在上面看到,所以它没有发生任何其他事情。但重点是,一个圆只有一个与多边形的接触,这意味着它只会在被报告时设置一个接触的冲动。另一个联系人,如果没有被重置,将具有最后一个要报告的对象的最后一个脉冲。

基本上,在圆圈上看到的冲动实际上是刚刚报告的任何内容留下的冲动。要修复它,请执行以下操作:

private static var s_impulse:b2ContactImpulse = new b2ContactImpulse();
public function Report(constraints:Vector.<b2ContactConstraint>) : void
{
    if (m_listener == null)
    {
        return;
    }

    for (var i:int = 0; i < m_contactCount; ++i)
    {
        s_impulse = new b2ContactImpulse();

        var c:b2Contact = m_contacts[i];
        var cc:b2ContactConstraint = constraints[ i ];

        for (var j:int = 0; j < cc.pointCount; ++j)
        {
            s_impulse.normalImpulses[j] = cc.points[j].normalImpulse;
            s_impulse.tangentImpulses[j] = cc.points[j].tangentImpulse;
        }
        m_listener.PostSolve(c, s_impulse);
    }
}

就这么简单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多