Setting up Box2d with LibGDX

Since I've been participating in One game a month, I've been trying out Box2d with LibGDX. There's some pretty good information on the different pieces here incase you want more info on the subject.

To start, create a new libgdx project. You can set it up using the gdx-setup-ui.jar or just create a new project in eclipse, and import the necessary jars into the project.

The jars i have are:

  • gdx-backend-lwjgl-natives.jar
  • gdx-backend-lwjgl.jar
  • gdx-natives.jar
  • gdx-openal.jar
  • gdx-setup-ui.jar
  • gdx-tools.jar
  • gdx.jar

Setup your usual base class, and setup a screen for us to test things in:

// MyGame.java
import com.badlogic.gdx.Game;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;


public class MyGame extends Game {
  
  private GameScreen gameScreen;
  
  public MyGame() {
    
  }
  
  public static void main(String args[]) {
    LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
    cfg.width = 800;
    cfg.height = 600;
    LwjglApplication app = new LwjglApplication(new MyGame(), cfg);
  }

  @Override
  public void create() {
    gameScreen = new GameScreen();
    setScreen(gameScreen);
  }
}
// GameScreen.java

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL10;


public class GameScreen implements Screen {

  @Override
  public void dispose() {
    // TODO Auto-generated method stub

  }

  @Override
  public void hide() {
    // TODO Auto-generated method stub

  }

  @Override
  public void pause() {
    // TODO Auto-generated method stub

  }

  @Override
  public void render(float arg0) {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

  }

  @Override
  public void resize(int arg0, int arg1) {
    // TODO Auto-generated method stub

  }

  @Override
  public void resume() {
    // TODO Auto-generated method stub

  }

  @Override
  public void show() {
    // TODO Auto-generated method stub

  }

}

Now it's time for the box2d bits. Box2d doesn't work in pixels, but in more real-world measurements of meters, kilometers an hour, and kilograms. I'm just concerned about the meters to pixels ratio for now, at least for this demo. Setup a couple constant properties in the GameScreen.

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL10;


public class GameScreen implements Screen {

  private static final float WORLD_TO_BOX = 0.01f;
  private static final float BOX_TO_WORLD = 100f;

  // ...
}

Lets setup the world. Add the following properties, much like the two above:

private World world;
private Box2DDebugRenderer debugRenderer;

The world is essentially the container of box2d. It is essential to add box2d physics to your game. The debugRenderer is so we can easily see what's happening. In the show method, set these values up:

public void show() {
    world = new World(new Vector2(0, -10), true);
    debugRenderer = new Box2DDebugRenderer();
}

The vector specifies the gravity. 0 because we dont want horizontal gravity, -10 so you get pulled downwards towards y = 0.

To setup some basic rendering, setup the OrthographicalCamera:

private OrthographicCamera camera;

Then initialize it as well in the show method:

camera = new OrthographicCamera();
camera.setToOrtho(false);

Now, setup the render method:

public void render(float delta) {
    camera.update();
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

    // physics updates

    Matrix4 cameraCopy = camera.combined.cpy();
    debugRenderer.render(world, cameraCopy.scl(BOX_TO_WORLD));

    world.step(1/60f, 6, 2);

}

The camera is being updated, and the screen being cleared. Then using a copy of the Matrix4, we pass that in to the debugRenderer, and modify it by the box to world ratio. The reason for this is so the fixtures and shapes you create onto the world are positioned as you want them to be. We then call the world.step, which progresses the physics with your game loop. The 1/60f translates to 60 frames per second. The second value is for velocityIterations, the second positionIterations. Ive been using the default values from the documentation listed above, and it's worked well for me. I haven't experimented with it much to tell you what's best.

Time to setup some actual objects! The game I've been working on is a sidescroller. So let's setup two things: a ground and a box representing a game entity. To setup the ground box and the entity box, we'll need to setup multiple properties:

private BodyDef groundDef;
private Body groundBody;
private BodyDef playerDef;
private Body playerBody;

Then initialize them like so again in the show method:

groundDef = new BodyDef();
groundDef.position.set(new Vector2((Gdx.graphics.getWidth() / 2) * WORLD_TO_BOX, 16f * WORLD_TO_BOX));
groundBody = world.createBody(groundDef);
PolygonShape groundShape = new PolygonShape();
groundShape.setAsBox((Gdx.graphics.getWidth() / 2) * WORLD_TO_BOX, 16f * WORLD_TO_BOX);
groundBody.createFixture(groundShape, 0f);
groundShape.dispose();

// the player box

playerDef = new BodyDef();
playerDef.type = BodyType.DynamicBody;
playerDef.position.set(new Vector2(100 * WORLD_TO_BOX, 400 * WORLD_TO_BOX));
playerBody = world.createBody(playerDef);

PolygonShape playerShape = new PolygonShape();
playerShape.setAsBox(50 * WORLD_TO_BOX, 50 * WORLD_TO_BOX);

FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = playerShape;
fixtureDef.density = 0.5f; 
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f;

Fixture fixture = playerBody.createFixture(fixtureDef);

playerShape.dispose();

There's a lot of code there, so here's a run down. The first bit sets up the ground body definition, the ground body and a shape to define its size. When making a static body that isnt effected by things like gravity, that's about all you need. Set the position to the center of the would be object. Since I wanted this box to be the width of the screen and 32 px high, I set it half the screen for x, and then 16px up for y. To fill the screen, I then setup the size. The setAsBox method accepts half height and half width values, so i devided the screen by 2, and specified 16 for the height. Once the fixture is created, and the shape is passed to it, we no longer need the shape, so it can be disposed.

The player def and body bits are fairly similar, however as you can see, it's being set to a dynamic body. The position and shape are setup in the same way as the ground, however in this case I'm creating a custom fixture. The custom fixture allows you to setup all the neat things like its density, friction and so forth. Restitution is float a value from 0-1. 1 meaning when it collides with a static object, it will bounce up back to where it was. I set it to .6, so it bounces by 60% of previous height. Play around with these to customize the feel of your game, and to find the right result you're looking for. Then after that the fixture is set, and the shape is then disposed. So long as you have the render method setup properly, you should see these objects when you run the program.

Well I hope this helps. Some of the camera stuff really bit me hard until I figured it out. If you want my full gamescreen.java code, it can be found here

If you run into any issues, feel free to post a comment, or hit me up on twitter