Autor Wątek: [Box2D] EdgeShape - problem z definicją/kolizją  (Przeczytany 404 razy)

Offline cybergod

  • Użytkownik

# Lipiec 03, 2018, 10:45:13
Uczę się właśnie biblioteki Box2D i mam pewien problem. Chcę sobie napisać platformówkę. Udało mi się zrobić ruch gracza po platformach, no ale platformy zdefiniowane jako PolygonShape doprowadzają do tzw. ghost collision, więc powinienem je zdefiniować jako EdgeShape. I tu jest problem: gracz w ogóle nie koliduje z platformą zdefiniowaną jako EdgeShape, ale wyświetla się tam, gdzie ma być. W obu przypadkach platforma ma ustawiony typ b2_staticBody, a pozycję i rozmiar podaję w pikselach i zamieniam później na metry. Nie mam pojęcia co robię nie tak. Do rysowania używam SFML.

Tutaj kod definujący paltformę jako EdgeShape:
void Object::InitAsEdgeBody(b2World *world, sf::FloatRect rect,
b2BodyType type, void *userData, bool originBasedPosition, float friction,
float restitution, bool isSensor)
{
        //parametr rect to pozycja i rozmiar obiektu w pikselach

size = sf::Vector2f(rect.width, 1.f); //rozmiar obiektu w pikselach

b2BodyDef bodyDef;

b2Vec2 bodyPosition;
if (!originBasedPosition) //pozycja liczy się od lewego górnego rogu obiektu
{
bodyPosition.x = (rect.left + size.x / 2) / 32.f; //pixels to meters
bodyPosition.y = (rect.top + size.y / 2) / 32.f; //pixels to meters
}
else //pozycja liczy się od środka obiektu
{
bodyPosition.x = rect.left / 32.f; //pixels to meters
bodyPosition.y = rect.top / 32.f; //pixels to meters
}

bodyDef.position = bodyPosition;
bodyDef.type = type;
body = world->CreateBody(&bodyDef);

b2EdgeShape bodyShape;
b2Vec2 v1 = bodyPosition;
b2Vec2 v2 = b2Vec2((bodyPosition.x*32.f + size.x) / 32.f, bodyPosition.y);

b2Vec2 v0 = b2Vec2((bodyPosition.x*32.f - size.x) / 32.f, bodyPosition.y);
b2Vec2 v3 = b2Vec2((bodyPosition.x*32.f + size.x) / 32.f, bodyPosition.y);

bodyShape.Set(v1, v2);
bodyShape.m_vertex0 = v0;
bodyShape.m_vertex3 = v3;
bodyShape.m_hasVertex0 = true;
bodyShape.m_hasVertex3 = true;

b2FixtureDef fixtureDef;
fixtureDef.friction = friction;
fixtureDef.restitution = restitution;
fixtureDef.isSensor = isSensor;
fixtureDef.userData = userData;
fixtureDef.shape = &bodyShape;
body->CreateFixture(&fixtureDef);
}

Dla porównania kod definiujący działającą platformę jako PolygonShape:
void Object::InitAsRectangularBody(b2World *world, sf::FloatRect rect,
b2BodyType type, void *userData, bool originBasedPosition, float friction,
float restitution, bool isSensor)
{
size = sf::Vector2f(rect.width, rect.height);
b2BodyDef bodyDef;

b2Vec2 bodyPosition;

if (!originBasedPosition)
{
bodyPosition.x = (rect.left + size.x / 2) / 32.f; //pixels to meters
bodyPosition.y = (rect.top + size.y / 2) / 32.f; //pixels to meters
}
else
{
bodyPosition.x = rect.left / 32.f; //pixels to meters
bodyPosition.y = rect.top / 32.f; //pixels to meters
}

bodyDef.position = bodyPosition;
bodyDef.type = type;
body = world->CreateBody(&bodyDef);

b2PolygonShape bodyShape;
bodyShape.SetAsBox(rect.width / 2 / 32.f, rect.height / 2 / 32.f); //pixels to meters

b2FixtureDef fixtureDef;
fixtureDef.friction = friction;
fixtureDef.restitution = restitution;
fixtureDef.isSensor = isSensor;
fixtureDef.userData = userData;
fixtureDef.shape = &bodyShape;
body->CreateFixture(&fixtureDef);
}

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Avaj

  • Użytkownik

# Lipiec 03, 2018, 16:36:52
Strzał w ciemno, próbowałeś odwrócić kolejność wierzchołków?

Offline cybergod

  • Użytkownik

# Lipiec 03, 2018, 17:32:31
Dzięki za odpowiedź, ale właśnie udało mi się rozwiązać problem.

Więc, rzecz była w tym, że w Box2D współrzędne wierzchołków działają w następujący sposób:
-jeśli kształt (b2PolygonShape, b2EdgeShape, etc.) nie jest dołączony do ciała, to współrzędne traktowane są jako współrzędne świata (globalne)
-jeśli kształt jest dołączony do ciała, to współrzędne wierzchołków traktowane są jako współrzędne lokalne, względem pozycji środka ciała

Wykorzystując powyższe informacje, zmieniłem definicję wierzchołków EdgeShape na następującą (reszta kodu bez zmian):
b2Vec2 v1 = b2Vec2(-size.x/2/32.f, -size.y/2/32.f),
v2 = b2Vec2(size.x/2/32.f, -size.y/2/32.f),
v0 = b2Vec2(-size.x/32.f, -size.y/2/32.f),
v3 = b2Vec2(size.x/32.f, -size.y/2/32.f);

I teraz wszystko działa tak, jak trzeba.
« Ostatnia zmiana: Lipiec 03, 2018, 18:22:11 wysłana przez programista12 »