1
\$\begingroup\$

I load my rectangular shapes from a simple Tiled level into libGDX and want to create a physics world out of it via Box2D and attach sprite assets for rendering.

I get the tiled object layer and iterate over it, create the objects and add it to the world:

    BodyDef bdef = new BodyDef();
    bdef.type = BodyDef.BodyType.DynamicBody;
    FixtureDef fdef = new FixtureDef();
    Shape shape;
    Sprite sprite = null;
    for(MapObject mo : layer.getObjects())
    {
       if (mo instanceof RectangleMapObject)
       {
         shape = getRectangle((RectangleMapObject) mo);
         sprite = new Sprite(box_texture, 0, 0, box_texture.getWidth(), box_texture.getHeight());
       }
       fdef.shape = shape;

       Body body = world.createBody(bdef);
       body.createFixture(fdef);

       if (sprite != null) {
             body.setUserData( sprite );
       }

        shape.dispose();
    }

    private Shape getRectangle(RectangleMapObject rectangleObject)
        {
            System.out.println("Loading rectangle from map file");

            Rectangle rectangle = rectangleObject.getRectangle();
            PolygonShape polygon = new PolygonShape();
            Vector2 size = new Vector2((rectangle.x + rectangle.width * 0.5f) / Config.PIXEL_PER_METER,
                    (rectangle.y + rectangle.height * 0.5f ) / Config.PIXEL_PER_METER);
            polygon.setAsBox(rectangle.width * 0.5f / Config.PIXEL_PER_METER,
                    rectangle.height * 0.5f / Config.PIXEL_PER_METER,
                    size,
                    0.0f);
            return polygon;
        }

The Box2D Debug Renderer shows everything fine. So, this works for Box2D.

But now I want to render the attached sprite for those object.

In render() I do it like:

    Gdx.gl.glClearColor(0, 0, 0.2f, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    handleInput();

    world.step(delta, 6, 3);

    // set camera to follow player
    gameCamera.position.set(
            player.getPosition().x * Config.PIXEL_PER_METER + Config.WIDTH / 4,
            Config.HEIGHT / 2,
            0
    );

    gameCamera.update();

    if(Config.DEBUG)     // move B2D camera with player
    {
        B2DCamera.position.set(
                player.getPosition().x + (Config.WIDTH / 4 / Config.PIXEL_PER_METER),
                (Config.HEIGHT/ 2 / Config.PIXEL_PER_METER),
                0
        );

        B2DCamera.update();
    }

sb.setProjectionMatrix(gameCamera.combined);
sb.begin();
            world.getBodies(tmp);
            for(Body b : tmp)
            {
               if(b.getUserData() != null && b.getUserData() instanceof Sprite)
               {
                        Sprite sprite = (Sprite) b.getUserData();
                        sprite.setPosition( b.getPosition().x * Config.PIXEL_PER_METER - sprite.getWidth() / 2, b.getPosition().y * Config.PIXEL_PER_METER - sprite.getHeight() / 2);
                        sprite.setRotation(b.getAngle() * MathUtils.radiansToDegrees);
                        sprite.draw(sb);
                    }
                }
sb.end();

if(Config.DEBUG)
   b2dr.render(world, B2DCamera.combined);

But the sprite rendering seems to be at the wrong place. While the Box2D debug draw is fine, the sprites are heavily off. I debugged it, and the box2d body position seems to be wrong. It's not a Pixel/Meter conversion issue, the values are not THAT wrong as far as I see, but also not just a rectangle length (more like randomly somewhere far away). I didn't set the body position explizitely, but implicitely via the recangle shape of the fixture. I thought that's sufficient. And DebugDraw was fine with that.

So, when I set the position of the body explicitly like this when creating the physics world:

bdef.position.x = mo.getProperties().get("x", Float.class) / Config.PIXEL_PER_METER;
bdef.position.y = mo.getProperties().get("y", Float.class) / Config.PIXEL_PER_METER;

and remove the position of the fixture like that:

polygon.setAsBox(rectangle.width * 0.5f / Config.PIXEL_PER_METER, rectangle.height * 0.5f / Config.PIXEL_PER_METER);

it seems to work well. Since it seems to be much easier for me to deal with shape and fixture positions than setting body position, I'd like to understand what's going wrong in my first run.

So, when I don't set the body position explicitly (but only the fixtures position via shape), why is the Box2D DebugRendering fine, where the sprites are not ? The Sprites draw on body's x/y pos, and this is not set correctly as far as I can see. But looking at the source of the DebugRenderer, it's also using body.getPosition() ? So I would expect this is also not working. But it does.

Any idea would be helpful. Maybe I just don't understand the concept of fixture position and body position ?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The fixture position in box2d is in relation to the body position. So if you set your fixture to be at (5, 5) the body is still at (0, 0) and if you then move the body to (1, 0), the fixture will then draw at (6, 5).

It looks like you are getting your sprite position from the Body position, not the fixture position in the original method. In the second one, you are setting the body, and leaving the fixture centered on it, so the sprites draw correctly.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .