Box2d As3联系监听问题

发布于 2024-10-13 22:03:26 字数 1074 浏览 5 评论 0原文

我在使用 box2d as3 b2ContactListener 类时遇到问题。我有一个名为 ContactListener 的类,它扩展 b2ContactListener 并重写 PostSolve 方法。 PostSolve 采用 2 个参数,contact 保存有关有接触的 2 个对象的信息,impulse 保存有关接触的信息。我使用脉冲参数来决定两个物体撞击的力度,然后相应地施加伤害。

问题是这样的: 如果我制作任何圆形物体,并让它在作为地面的静态物体上慢慢滚动,然后将一个相当大的物体扔到地面上的任何地方,则运动中的圆圈将产生接触,从而产生重复的脉冲大,适合滚动。它会导致滚动的圆形物体在不应该破裂的时候破裂。

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

谁能解释一下情况吗?这是一个已知问题吗?解决方法?

我使用的是 Box2DAs3 版本 2.1a。

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

更新:我已经进一步缩小了问题范围。当一个大物体的平坦边缘撞击我的地面物体时,接触听者会惊慌失措并应用质量脉冲。任何醒着并接触地面的物体(不仅仅是圆圈)都会收到大量的 PostSolve 方法调用。我尝试将一个大小为 11 像素 x 11 像素的盒子扔到地面上,同时一个圆圈在地面上滚动。该错误没有发生。但是,如果盒子是 12 x 12,则确实会出现错误。另外,如果我将尺寸为 12 x 12 的盒子旋转到 0.1 度,则不会出现该错误。需要有足够大的接触面积才能进行复制。盒子的密度也不会产生任何影响。另外,如果盒子是一个宽度为 10、高度为 100 的矩形,该 bug 也会重现。几乎就像是物体的大小导致了错误,可能不是接触面积的大小。

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

链接

I'm having a problem with the box2d as3 b2ContactListener class. I have a class named ContactListener that extends b2ContactListener and overrides the PostSolve method. PostSolve takes 2 parameters, contact which holds the info about the 2 objects that have contact, and impulse which holds info about the contact. I'm using the impulse parameter to decide how hard 2 objects hit and then I apply damage accordingly.

Here is the problem:
If I make anything that is circular, and let it slowly roll on the static body I have as the ground, then drop a fairly large object anywhere on the ground, the circle while in motion will get contacts will a repeating impulse that is way to large for just rolling. It causes the rolling circular objects to break when they shouldn't.

Its almost as if its shaking the static body and causing massive damage to objects hundreds of meters away, but it only affects circles.

Can anyone shed some light on the situation? Is this a known issue? Workarounds?

I am using Box2DAs3 version 2.1a.

Update: Once the body enters this weird state of applying to much damage, any circle that touches it gets tons of large impulses. Once something non circular come in contact with the body, it no longer has the problem. Also this problem is not only on static objects but dynamic and kinematic as well.

Update: I have narrowed the problem down further. The contact listener freaks out and apply's mass impulses when the flat edge of a large object hits my ground object. Any object, not just circles, that is awake and touches the ground will get tons of PostSolve method calls. I tried dropping a box with a size of 11 pixels by 11 pixels onto the ground while a circle was rolling on the ground. The bug did not happen. However if the box is 12 by 12 the bug does occur. Also if i rotate a box with a size of 12 by 12 to 0.1 degrees, the bug does not occur. There needs to be a large enough contact area for it to repro. Also density of the box does not effect anything. Also if the box is a rectangle with a width of 10 and height of 100 and the bug will repro. It's almost like just the size of the object is causing the bug, possibly not the area of contact size.

Update: Here is a link to a Box2D forum post I made that has an example swf with source.

Link

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

尽揽少女心 2024-10-20 22:03:26

哇。所以我终于知道问题出在哪里了。

经过几个小时的尝试,通过在 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 var 是静态的,因此对于 b2Island 类的每个实例都是相同的(如果有多个实例),而且它在任何时候都不会重置。所有对 s_impulse var 的引用都可以在上面看到,所以它没有发生任何其他事情。但重点是,一个圆只与一个多边形有一次接触,这意味着在报告时它只会为一个接触设置脉冲。另一个触点如果没有被重置,将具有要报告的最后一个对象的最后一个脉冲。

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

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);
    }
}

就这么简单。

WOW. So I've finally found out what the problem is.

After hours upon hours of trying to figure out if there is a workaround by doing something fancy in the ContactListener, I decided to look and see where the PostSolve method was being called from. It comes from a class named b2Island and it comes from the Report function in that class. At first glance I spotted the problem easily. Her is the function:

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);
    }
}

So yeah obviously the s_impulse var is static so it will be the same for every instance of the b2Island class ( if there is more then one ) and also it's not getting reset at any point. All the references to the s_impulse var can be seen above, so nothing else ever happens to it. But here's the point, a circle only has one contact with a polygon meaning it will only set the impulse for one contact when being reported. The other contact, if not being reset will have the last impulse of the last object to be reported.

Basically the impulses seen on the circle is actually left over impulse from whatever just got reported. To fix it do this:

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);
    }
}

It's as simple as that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文