Box2D - Как я могу узнать, когда 2 прибора соприкасаются? - PullRequest
2 голосов
/ 22 февраля 2012

Мне просто любопытно, в случае, если у меня есть тело, в котором есть 2 или более приборов, которые не «соединены вместе», как я могу определить это окончательно в коде? Вот пример того, что я имею в виду:

Example of a single body with more than 1 fixture, two are touching, one is not.

Я пометил вершины для каждого отличительного приспособления, чтобы было совершенно ясно, что это отдельные фигуры, которые не разделяют вершины друг с другом. Однако они объединены в одно тело. Как вы можете видеть, два светильника находятся в непосредственной близости друг от друга или «касаются», а один отделен отдельно. Мне интересно, как я могу запросить приборы тела в Box2D, чтобы иметь возможность выяснить это во время выполнения.

Чтобы представить все это в перспективе, оно предназначено для создания и обработки разрушаемых тел. Изображение представляет собой грубое представление о том, что произойдет после того, как отверстие будет пробито через набор приспособлений в теле. Мне нужно узнать, какие приборы соприкасаются друг с другом, чтобы я мог разделить одно тело на два, как, естественно, и должно быть в этот момент.

Ответы [ 4 ]

3 голосов
/ 22 февраля 2012

Если вы уже подготовили новые приборы, вы можете использовать функцию b2TestOverlap, чтобы проверить, перекрывают ли они . Функция находится в b2Collision.h:

/// Determine if two generic shapes overlap.
bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,
                    const b2Shape* shapeB, int32 indexB,
                    const b2Transform& xfA, const b2Transform& xfB );

Формы можно найти с помощью fixture-> GetShape (), а параметры индекса для полигонов будут равны нулю. Поскольку приборы находятся в одном теле, оба последних параметра могут быть body-> GetTransform ().

Я никогда не использовал это сам, поэтому не могу сказать вам наверняка, но, отмечая, что название этой функции - «перекрытие», оно может не дать положительного значения для случая ваших приборов A и B на диаграмме. технически я не думаю, что они перекрываются. Если это так, я думаю, что вы один, потому что Box2D не предлагает никаких «трогательных» тестов.

кстати, список контактов, упомянутый Константином, действителен только для осветительных приборов на разных телах - осветительные приборы на одном теле не сталкиваются.

2 голосов
/ 22 февраля 2012

В руководстве Box2D под "9.3 Доступ к контактам" написано, что вы можете получить доступ ко всем контактам тела, используя функцию GetContactList:

for (b2ContactEdge* ce = myBody->GetContactList(); ce; ce = ce->next)
{
    b2Contact* c = ce->contact;
    ...
}

В b2ContactEdge и b2Contact вы можете найти фактические фигуры и флажки, если они действительно касаются (b2Contact::IsTouching).

1 голос
/ 22 февраля 2012

Я бы предложил сделать что-то вроде этого:

  • , чтобы получить точный результат, вам действительно нужно проверить пересечения. В первом проходе вы можете сравнить только центры тяжести приборов, а затем вычислить пересечения всех линий, только если COG находятся на небольшом расстоянии.

  • другим подходом может быть растеризация сцены. тогда вы можете рисовать растеризованные пиксели, используя что-то вроде буфера трафарета.

  • в этом случае трафарет будет массивом размера (w * h), где w и h - ширина и высота растрового изображения и содержит целое число на пиксель.

  • инициализировать буфер трафарета 0 для каждого пикселя.

  • для каждого растеризованного прибора, который вы «рисуете», вы просто увеличиваете значение буфера для всех его положений в пикселях.

  • поэтому, наконец, буфер трафарета содержит 0 в позициях, которые не заняты никаким прибором, 1, где только один прибор находится в позиции и для любого большего значения у вас есть пересечения.

тогда сложность этого подхода в основном зависит от выбранного разрешения растеризации.

0 голосов
/ 10 февраля 2017

Другим способом сделать это (в качестве альтернативы использованию b2TestOverlap, как было предложено ранее кем-то другим), было бы использование функции b2CollidePolygons (из b2Collision.h). Вы можете использовать это для многоугольников форм приборов, а затем посмотреть, будет ли поле b2Manifold pointCount больше нуля.

Вот несколько примеров кода до C ++ 11 для вас (который я не скомпилировал и не протестировал, поэтому, надеюсь, не слишком foobar'ed):

bool isTouching(const b2PolygonShape& polygonA, const b2Transform& xfA, const b2PolygonShape& polygonB, const b2Transform& xfb)
{
    b2Manifold manifold;
    b2CollidePolygons(&manifold, &polygonA, xfA, &polygonB, xfB);
    return manifold.pointCount > 0;
}

bool isPolygonFixturesTouching(const b2Fixture& fixtureA, const b2Fixture& fixtureB)
{
    const b2Shape* shapeA = fixtureA.GetShape();
    const b2Shape* shapeB = fixtureB.GetShape();
    if (shapeA->GetType() == b2Shape::e_polygon && shapeB->GetType() == b2Shape::e_polygon)
    {
        const b2Body* bodyA = fixtureA.GetBody();
        const b2Transform& xfA = bodyA->GetTransform();
        const b2Body* bodyB = fixtureB.GetBody();
        const b2Transform& xfB = bodyB->GetTransform();
        return isTouching(*(static_cast<b2PolygonShape*>(shapeA)), xfA, *(static_cast<b2PolygonShape*>(shapeB)), xfB);
    }
    return false;
}

int main()
{
    ...
    if (isPolygonFixturesTouching(fixtureA, fixtureB))
    {
        std::cout << "hooray!" << std::endl;
    }
}

Примечание: Некоторые грубые временные тесты, которые я только что попробовал, сравнивают b2TestOverlap с b2CollidePolygons, показывая b2TestOverlap, чтобы быть в 4 или 5 раз быстрее (чем b2CollidePolygons). Учитывая, что первый ищет только перекрытие, в то время как последний вычисляет коллизионный коллектор, я полагаю, что разница в скорости не удивительна. В любом случае, похоже, мораль этой истории такова, что b2TestOverlap, вероятно, является предпочтительной функцией, если вы просто хотите знать, касаются ли 2 прибора, тогда как b2CollidePolygons более полезна, если вы также хотите узнать дополнительные вещи, например, как 2 светильника соприкасаются.

...