Box2d As3 проблема контактного слушателя


У меня проблема с классом box2d as3 b2ContactListener. У меня есть класс с именем ContactListener, который расширяет b2ContactListener и переопределяет метод PostSolve. PostSolve принимает 2 параметра, контакт, который содержит информацию о 2 объектах, имеющих контакт, и импульс, который содержит информацию о контакте. Я использую параметр impulse, чтобы решить, насколько сильно бьют 2 объекта, а затем наношу урон соответственно.

Вот в чем проблема: Если я сделаю что-нибудь круглое, и пусть он медленно катится по статическому телу, которое у меня есть как земля, затем бросьте довольно большой объект в любом месте на земле, круг в то время как в движении будет получать контакты будет повторяющийся импульс, который является большим для просто прокатки. Это заставляет вращающиеся круговые объекты ломаться, когда они не должны.

Это почти так же, как если бы он сотрясал статическое тело и наносил огромный ущерб объектам в сотнях метров от него, но это только влияет на круги. Может ли кто - нибудь пролить свет на эту ситуацию? Это известная проблема? Обходные пути?

Я использую Box2DAs3 версии 2.1 a.

Обновление: Как только тело входит в это странное состояние нанесения большого ущерба, любой круг, который касается его, получает тонны больших импульсов. Как только что-то некруглое входит в контакт с телом, у него больше нет проблемы. Кроме того, эта проблема касается не только статических объектов, но и динамических и кинематических.

Update: я еще больше сузил проблему. Контакт слушатель пугается и применяет импульсы массы, когда плоский край большого объекта ударяется о мой наземный объект. Любой объект, а не только круги, которые просыпаются и касаются земли, получит тонны вызовов метода PostSolve. Я попытался бросить коробку размером 11 на 11 пикселей на землю, в то время как круг катился по земле. Ошибки не произошло. Однако, если поле 12 на 12, ошибка действительно возникает. Кроме того, если я поворачиваю коробку размером 12 на 12 на 0,1 градуса, ошибка не возникает. Там должна быть достаточно большая площадь контакта для его повторного использования. Также плотность коробки ни на что не влияет. Также если коробка представляет собой прямоугольник шириной 10 и высотой 100 то и жучок будет повторяться. Это почти как просто размер объекта вызывает ошибку, возможно, не размер области контакта.

Update: Вот ссылка на сообщение на форуме Box2D, которое я сделал, которое имеет пример swf с исходным кодом.

Ссылка

1 3

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

Все очень просто.