Box2d As3 проблема со слушателем контакта - PullRequest
3 голосов
/ 26 января 2011

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

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

Это почти как если бы оно сотрясало статическое тело и наносило огромный урон объектам на расстоянии сотен метров, но это затрагивало только круги.

Может кто-нибудь пролить свет на ситуацию?Это известная проблема?Обходные пути?

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

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

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

Обновление: Вот ссылка на сделанное мной сообщение на форуме Box2D, в котором естьПример SWF с источником.

Ссылка

1 Ответ

0 голосов
/ 05 марта 2011

WOW. Итак, я наконец выяснил, в чем проблема.

После долгих часов попыток выяснить, есть ли обходной путь, выполняя что-то необычное в 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 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);
    }
}

Это так просто.

...