2
\$\begingroup\$

LibGdx sprite rotation vs Box2D physics rotation problem

Tearing my hair out on this one. I am an experienced software developer, but very new to LibGdx and Box2D development.

I am writing a game where the game board is the size of the screen. The game board does not pan - it just fills the screen. For the descriptions below presume that the device is being held vertically, so that vertical is the longest length. Also, for the description below, presume that on a device with a 'normal' aspect ratio, circles will be rendered perfectly circular, but a device that is narrower than expected, the circles will be squashed so that they are taller than wide.

I have a number of circle shapes that are rendered to the screen.

Because different devices will have different width / height aspect ratios, I am happy for the circle shapes to be squashed on a device that is narrower on the horizontal than expected (I am trying to avoid maintaining identical aspect ratios and forcing black borders at the edges of the game board).

My problem is this: when Box2D debug renders the screen, showing the physics objects, the circle shapes maintain their width and height, even when rotated. To describe further, if a sphere is displayed with 0 degree rotation on a narrow device, it takes an oval shape that is taller than it is wide, as would be expected on a narrower than expected device. If you rotate the circle shape by 90 degrees, the Box2d debug renderer shows the rotation (there is a line that sticks out of the centre of the object at an angle that shows the angle of rotation) but the object maintains its taller than wide oval shape. This is correct, as a sphere on a horizontally narrower aspect-ratioed device will always be displayed taller than wide.

When I attempt to overlay a LibGDX sprite on top of the Box2D physics simulation (the sprite, in its unaltered form, is circular, and is then scaled to the devices aspect ratio), with a zero degree angle, it appears nicely mapped to the Box2D representation - taller than it is wide. However, when I rotate the LibGDX sprite by 90 degrees, it appears rotated the way a billboard image would be rotated, so it is now wider than it is tall (imagine drawing a taller-than-wide oval on a piece of paper and turning the piece of paper by 90 degrees).

It appears to me that Box2D applies rotation before it applies the camera scaling - so the circular object is rotated first (maintaining its circular shape under the hood), and then sqaushed to form an ellipse that is taller than wide on the screen. Whereas, the LibGDX engine applies the transforms in reverse. The object is squashed to taller-than-wide, then rotated, so it becomes wider-than-tall on the screen.

I have pasted the relevant code below:

//screen size in box2D metres
private static float screenHeight = 100.0f;
private static float screenWidth = 70.0f;

//set up the camera in the show() method
    cam = new OrthographicCamera(screenWidth, screenHeight);  
    cam.position.set(screenWidth / 2, screenHeight / 2, 0);

//render method
batch.begin();
for (int i = 0; i < ballList.length; i++)
{
    ballList[i].render(batch);
}
batch.end();

//ball class render method
public void render(SpriteBatch batch)
{
    ballHappyImage.setOrigin(64.0f, 64.0f);
    ballHappyImage.setPosition(body.getPosition().x - 64.0f, body.getPosition().y - 64.0f);
    float scaleWidth = Gdx.graphics.getWidth() / 1400.0f; //hardcoded to make things fit correctly
    float scaleHeight = Gdx.graphics.getHeight() / 2000.0f; //hardcoded to make things fit correctly
    ballHappyImage.setRotation(body.getAngle() * MathUtils.radiansToDegrees);
    ballHappyImage.setScale(scaleWidth, scaleHeight);
    ballHappyImage.draw(batch);
}

The images below show the Box2D debug rendered line drawings overlayed on the libgdx sprites.

enter image description here

enter image description here

\$\endgroup\$
  • 1
    \$\begingroup\$ This isn't an answer, but the libgdx-utils library has a Box2DSprite class that takes care of all the difficulties in synchronizing the appearance with the physics body. It may be helpful to either use this library or see how they implemented the functionality you are looking for: bitbucket.org/dermetfan/libgdx-utils/wiki/Home \$\endgroup\$ – Dashto May 13 '14 at 18:46
  • \$\begingroup\$ Thanks, Dashto. I'll try this tomorrow and let you know how it goes. \$\endgroup\$ – Daniel Wild May 14 '14 at 20:01
  • 1
    \$\begingroup\$ I tried this today and it works beautifully. The sample at 'bitbucket.org/dermetfan/somelibgdxtests/src/…' shows everything clearly. Thanks Dashto. BTW - do we assign points for correct answers on stackexchange? \$\endgroup\$ – Daniel Wild May 18 '14 at 11:03
  • \$\begingroup\$ I've reposted my comment as an answer with a small code sample, if you're looking to accept one. I'm glad to have helped! \$\endgroup\$ – Dashto May 18 '14 at 17:12
3
\$\begingroup\$

The libgdx-utils library has a Box2DSprite class that takes care of all the difficulties in synchronizing the appearance with the physics body. It may be helpful to either use this library or see how they implemented the functionality you are looking for: bitbucket.org/dermetfan/libgdx-utils/wiki/Home

Example:

bodyDef.position.set(4f, 8);
bodyDef.angularVelocity = 5;

PolygonShape boxShape = new PolygonShape();
boxShape.setAsBox(2.5f, 3);

fixtureDef.shape = boxShape;
fixtureDef.density = 5;
fixtureDef.friction = .4f;
fixtureDef.restitution = .2f;

Body box = world.createBody(bodyDef);
box.createFixture(fixtureDef);
box.setUserData(new Box2DSprite(Assets.someImage));

ballShape.setPosition(new Vector2(-Box2DUtils.getWidth(boxShape), 0));;
fixtureDef.shape = ballShape;

box.createFixture(fixtureDef);

boxShape.dispose();
\$\endgroup\$
2
\$\begingroup\$

Try

sprite.setOriginCenter();

This should help

\$\endgroup\$
  • 1
    \$\begingroup\$ It would be useful if you edited the answer to include why this should help. What problem does it solve and how does it solve it? \$\endgroup\$ – MichaelHouse Dec 15 '14 at 15:30
  • 1
    \$\begingroup\$ That is easily done by referencing the API and JavaDoc for the the function in the libgdx code and not rpeeated here to become stale and out of date. \$\endgroup\$ – HörmannHH Mar 18 '15 at 21:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.