I'm working on a platformer and I've chosen to use Box2D for physics but I'm having trouble converting meters to pixels. I have a static object and a dynamic object. The dynamic object falls onto the static object but when the dynamic object hits the static object, they don't touch, they're about a meter apart when they're supposed to be touching.
As you can see from the screenshot, the dynamic object (rat) is hovering above the static object (blue rectangle) when they're supposed to be touching. I assumed it was a problem with my meters-to-pixels code so I fiddled with it and inspected variables in the debugger and still can't figure out what I'm doing wrong.
Rendering is done in pixels (via SDL2) and the origin is in the top-left corner of the window. +x is right and +y is down.
Physics is done in meters (via Box2D) and the origin is in the bottom-right corner of the window. +x is right and +y is up.
Heres the code to create the dynamic object.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.fixedRotation = true;
b2Body *body = world.CreateBody(&bodyDef);
b2PolygonShape shape;
shape.SetAsBox(1.0f, 1.0f);
b2FixtureDef fixtureDef;
fixtureDef.shape = &shape;
fixtureDef.density = 10.0f;
body->CreateFixture(&fixtureDef);
body->SetTransform({0.0f, 10.0f}, 0.0f);
And here's the code to create the static body
b2BodyDef bodyDef;
bodyDef.type = b2_staticBody;
b2Body *body = world.CreateBody(&bodyDef);
b2PolygonShape shape;
shape.SetAsBox(WINDOW_METER_SIZE.x, 2.0f);
b2FixtureDef fixture;
fixture.shape = &shape;
fixture.friction = 0.0f;
body->CreateFixture(&fixture);
body->SetTransform({0.0f, 0.0f}, 0.0f);
The Rect
and RectPx
classes represent a rectangle as a top-left point p
and a size s
.
To get the Rect
of the b2Body
used for drawing.
b2Body *body;
const Rect rect = {body->GetPosition(), {1.0f, 1.0f}};
Heres the code to transform a rectangle in meters to a rectangle in pixels
RectPx transform(const Rect rect) {
return {
{
rect.p.x * PIXELS_PER_METER,
(-rect.p.y + WINDOW_METER_SIZE.y - rect.s.y) * PIXELS_PER_METER
},
rect.s * PIXELS_PER_METER
};
}
I later use the RectPx
to call SDL_RenderFillRect
and SDL_RenderCopy
which both expect a rectangle in the described format.
I really hope there's an obvious mistake in my code somewhere that a Box2D guru can spot.
Thank you in advance for reading this very long question.