Box2d As3 接触监听器问题

3
我在使用box2d as3的b2ContactListener类时遇到了问题。我有一个名为ContactListener的类,它扩展了b2ContactListener并覆盖了PostSolve方法。PostSolve需要两个参数,contact保存有关接触的两个对象的信息,impulse保存有关接触的信息。我使用impulse参数来决定两个对象碰撞的强度,然后相应地应用伤害。
问题在于: 如果我制作任何圆形物体,并让它在我设置为地面的静态物体上缓慢滚动,然后在地面的任何位置放下一个相当大的物体,那么在运动中的圆形将接触到一种重复的脉冲,这种脉冲对于仅仅是滚动而言过于强大。这会导致滚动的圆形物体在不应该破裂时破裂。
这几乎就像是它在震动静态物体并对数百米之外的物体造成巨大的损坏,但它只影响圆形。
有人能解释一下这种情况吗?这是已知的问题吗?有解决办法吗?
我正在使用Box2DAs3版本2.1a。 更新: 一旦物体进入这种奇怪的状态,应用过多的伤害,任何接触它的圆形都会产生大量的冲力。一旦非圆形物体接触到物体,它就不再有问题了。这个问题不仅存在于静态对象上,还存在于动态和运动学对象上。 更新: 我把问题进一步缩小了。当大物体的平坦边缘撞击我的地面物体时,接触侦听器会出现问题,应用质量冲量。任何醒着的、接触地面的物体都将得到大量的PostSolve方法调用,不仅仅是圆形。我试着在一个圆形在地面上滚动时,让一个尺寸为11像素乘以11像素的盒子掉到地上。错误没有发生。然而,如果盒子是12×12,则会出现错误。如果我将一个尺寸为12×12的盒子旋转0.1度,错误就不会发生。需要有足够大的接触面积才能重现这个问题。盒子的密度对任何东西都没有影响。如果盒子是一个宽度为10,高度为100的矩形,那么错误将重现。好像只有物体的大小引起了错误,可能不是接触面积的大小。

更新:这里是我在Box2D论坛上发布的带有源代码示例的swf链接。

链接


我对box2d一无所知,但如果它影响静止的圆形和滚动的圆形,那么这实际上具有一定的物理意义。 - Beta
睡眠圆圈,处于沉睡和唤醒状态的多边形都不受其影响。 - Jordan
太有趣了!这听起来像是box2d中的一个bug,我认为不会有干净的解决方法。 - Beta
1
你能否发布一个链接来描述你所说的内容? - Zevan
@Zevan 我添加了一个示例链接。 - Jordan
1个回答

0

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

经过数小时的尝试,试图通过在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);
    }
}

就是这么简单。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接