libgdx

Setting up a basic LibGDX project

This topic came up on one of my favourite game development communities, r/gamedev and I thought I should make a quick tutorial on setting up Libgdx for someone new in game development, so you don't have to worry.

You can use the gdx-setup-ui.jar, but I'd recommend against it. It segregates projects, creating a core, an android one, and more if you check it off. This is confusing and unnecessary for someone new to the library. To just get a desktop project in eclipse, here's what you do:

  1. Create a new Java Project under File > New > Java Project
  2. Give it a name, and click finish.
  3. Right click on the project folder on the left hand screen.
  4. In the right-click dialogue, go into New > Folder. Give it the name "assets"
  5. Do this again, and create a "libs". You can call them whatever you wish, it's just what i like to use. Assets is for images and such, libs will store the LibGDX jars.

Here's how your project should look:

project1.jpg

Download libgdx from here. Be Sure to grab the latest stable build. Unzip the folder. There's a lot of stuff in here, what you'll generally need are the following files:

  • gdx-backend-lwjgl-natives.jar
  • gdx-backend-lwjgl.jar
  • gdx-natives.jar
  • gdx-openal.jar
  • gdx.jar

You can grab other ones as you need them, for example if you want to use Tiled

  • extensions/gdx-tiled-preprocessor.jar
  • extensions/gdx-tools.jar

Copy the .jar files, and put them into the libs directory in your java project folder.

Now add the jars in eclipse:

  1. Right click on the project name
  2. Click refresh so the folders get updated with the Jar files.
  3. Right click again & select build path
  4. In the sub menu, select Configure Build Path
  5. In the now open window, click Add Jars on the right.
  6. Expand the project folder, and then expand libs
  7. Shift click all the jar files in the folder.
  8. Click OK
project2.jpg

Now that you have all the necessary binaries, time to create a simple window to start.

Add a new class to the src package. Be sure to name it the same as the project, as it's where we'll add the main method.

In the class, add the following import statements:

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.Game;

LWJGL will be used to create the window. The import of the Game interface is for later. Setup your main method inside the class:

public static void main(String args[]) {
    LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
    cfg.width = 800;
    cfg.height = 640;
    cfg.useGL20 = false;
    LwjglApplication app = new LwjglApplication(new MyLibgdxGame(), cfg);
}

The setup here is pretty straight forward. We create a new configuration object to store the resolution of the window. We are not using OpenGL2.0, so set that to false. The last line is then creating a new application window, by passing this a new object of this class as the game. Eclipse will now complain there's a compiler error. To fix, extend your class with Game:

public class MyLibGdxGame extends Game {

Then add the interface method so the interface can be satisfied:

@Override
public void create() {

}

At this point you can build the game and a window will pop up. But it will flicker and such, which is not what we want. So what you can do now is add a new class.

  1. Call it GameScreen
  2. Add an interface to it in the creation wizard.
  3. The interface is called Screen and is part of com.badlogic.gdx package.
  4. Click finish

This class creates a lot of nice functionality for us to manage a game screen. You can use the screen interface for different states of the game. Such as menus, intro, game over, etc. It gives you initialization, a render method, pause, and other handy methods.

To solve our above problem, add the following line to the render method:

Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

This simply clears the screen with a black colour. It ensures that we won't get that flickering nonsense. Back in your main game class, add the screen to the game via:

 GameScreen gameScreen = new GameScreen();
 setScreen(gameScreen);

Put those in the create method, and try running the application. That's your basis on getting an application setup for libgdx. Definitely check out their documentation on how to use the framework. Just remember to start simple. Even just do some movement with shapes and such!

A note about assets. A lot of the tutorials refer to using the setup ui. Because of that, the assets load a bit differently. If you have a file in the assets folder called player.png, you can resolve that path simply using: Gdx.files.internal("assets/player.png")

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