Box2D body position out of sync with sprite

Started by
5 comments, last by BiiXteR 7 years, 12 months ago

As the title says. my Box2D bodies seem to be out of sync with the sprites.

The sprites move when the body does, however it isn't centered.

Not sure if this is because of the body's size or if it's the position that isn't correct.

PPM is the conversion number form meters to pixels :


#define PPM 20

And this is what my sprite creation function looks like :


Sprite::Sprite(std::string id, std::string filePath, Vector2 position, Vector2 size, float _density, float _friction, b2BodyType type)
{

	spriteId = id;

	surface = SDL_LoadBMP(filePath.c_str());
	if (surface == nullptr)
	{
		Errors::Error("Failed to load image!", __FILE__, __LINE__);
		return;
	}

	x = position.x;
	y = position.y;

	surface->w = size.x;
	surface->h = size.y;
	width = size.x;
	height = size.y;

	texture = SDL_CreateTextureFromSurface(Window::GetRenderer(), surface);
	SDL_FreeSurface(surface);
	surface = nullptr;


	density = _density;
	friction = _friction;

	bodyDef.type = type;
	bodyDef.gravityScale = 9.8f;
	bodyDef.position.Set(x, y);

	b2World* world = World::GetWorld();

	body = World::GetWorld()->CreateBody(&bodyDef);

	shape.SetAsBox(width / 2, height / 2);

	fixtureDef.shape = &shape;
	fixtureDef.density = density;
	fixtureDef.friction = friction;

	body->CreateFixture(&fixtureDef);
}

And this is my sprite drawing function :


void Sprite::Draw()
{
	//std::cout << body->GetPosition().x << "  " << body->GetPosition().y << std::endl;

	x = body->GetPosition().x / PPM;
	y = body->GetPosition().y / PPM;

	SDL_Rect rect;
	rect.x = x;
	rect.y = y;
	rect.w = width;
	rect.h = height;

	if (SDL_RenderCopy(Window::GetRenderer(), texture, NULL, &rect) < 0)
	{
		Errors::Error("Failed to render texture : " + spriteId, __FILE__, __LINE__);
		return;
	}

}

I'm very confused on when I should use / PPM or * PPM...

Edit :

I took a break form the project for a while, still couldn't understand what was wrong.

Here's a image to "visualize" what I mean and what my problem is.

The values in the console are the positions of each body in the world.

e5b6369cb3cb4ba1e0fb69bd641f7549.png

I'm still using the exact same code, except that I set my PPM to 1.

Edit 2 :

After even more printing out values, it seems like the bodies aren't colliding at all? o.o

Might just be stupid though, I'm really tired as I'm testing this.

Here's the "new" values :

223e3534b4db3c1c812e24c7819d6a97.png

Advertisement

Have you read Box2D's documentation, at page 65, section Pixels and Coordinate Systems? You are responsible for defining how many pixels a meter has according to the docs.

I suggest you to read the documentation carefully. It describes how to setup bodies correctly at its initial pages. (Maybe you're setting the rigid body as a sensor object or disabling collision with a collision filter or setting up a polygon incorrectly?). It can be many things.

Erin also suggests to use MKS in your game and only convert these units in the rendering code because convenience. This way you'd be setting the box as shape.SetAsBox(10.0f, 10.0f), which in this case it'll be a box of 20x20 m (because you pass the 10 half-width/height as parameters).

Have you read Box2D's documentation, at page 65, section Pixels and Coordinate Systems? You are responsible for defining how many pixels a meter has according to the docs.

I suggest you to read the documentation carefully. It describes how to setup bodies correctly at its initial pages. (Maybe you're setting the rigid body as a sensor object or disabling collision with a collision filter or setting up a polygon incorrectly?). It can be many things.

Erin also suggests to use MKS in your game and only convert these units in the rendering code because convenience. This way you'd be setting the box as shape.SetAsBox(10.0f, 10.0f), which in this case it'll be a box of 20x20 m (because you pass the 10 half-width/height as parameters).

So I could set it to whatever I want?

If yes, then pixel to meter conversion is not my problem...

Hi,

as has already been stated it is up to you to decide how many pixels there are in 1 meter. You just have to keep it constant across everything in one System.

This thread may also help you: http://www.gamedev.net/topic/667820-box2d-pixels-per-meter-scaling/

Moreover, as far as I know you can render a debugging screen of box2D which might help you with finding the problem.

Hi,

as has already been stated it is up to you to decide how many pixels there are in 1 meter. You just have to keep it constant across everything in one System.

This thread may also help you: http://www.gamedev.net/topic/667820-box2d-pixels-per-meter-scaling/

Moreover, as far as I know you can render a debugging screen of box2D which might help you with finding the problem.

I'd rather not make my code more messy unless needed, I'll add some code to my post and see if that leads somewhere. If not I'll go ahead and setup the DebugDrawing.

In box2D you are using setAsBox(halfWidth, halfHeight) to create the shape. That means the body's position relates to the center of the box.

However in your SDL rendering the position of SDL_Rect relates to the top-left corner of the texture.

So I expect that what you see at runtime is that the top-left corner of your texture is positioned at the center of the box2d body.

You either need to align your rendering with your physics, or vice-versa. Either offset your rendering x and y coords by the halfWidth and halfHeight. Or use a version of setAsBox which lets you specify a custom center position (and set it to the top-left corner to match with SDL).

In box2D you are using setAsBox(halfWidth, halfHeight) to create the shape. That means the body's position relates to the center of the box.

However in your SDL rendering the position of SDL_Rect relates to the top-left corner of the texture.

So I expect that what you see at runtime is that the top-left corner of your texture is positioned at the center of the box2d body.

You either need to align your rendering with your physics, or vice-versa. Either offset your rendering x and y coords by the halfWidth and halfHeight. Or use a version of setAsBox which lets you specify a custom center position (and set it to the top-left corner to match with SDL).

I added this in my drawing function :


x = body->GetPosition().x - width / 2;
y = body->GetPosition().y - height / 2;

Which also doesn't work :/

This topic is closed to new replies.

Advertisement