Perita

Headless libGDX and Tiled Maps Woes

We have reached a point in Flick Karts that has everything we need to test the gameplay: there is a placeholder circuit with barriers that we can zoom and pan, multiple pucks that can be moved and collide with each other, and the physics works well enough at this stage.

Pan, zoom, and flicking a placeholder puck.

It is now time to make it a multiplayer game.

We decided early on that this will be a turn-based multiplayer game: players take turns, in a round-robin fashion, to either move their puck or use an item until all players have completed all laps. One of the (many) errors i did with Boat Boom Boom was to wait too much before attempting to wedge in, as it were, network features, even though we decided from the start that it would be a multiplayer game. For some reason i though that, merely by keeping the logic and the rendering in separate packages, adding a multiplayer layer later on would not be “that hard”, and we concentrated on having everthing in place first. Of course, i found out that network code is not plug-and-play and had to refactor most of the gameplay classes. Even worse, i picked Kryonet as the networking library without realising that was not usable from GWT. Although, to be honest, we did not plan to make an HTML5 version of Boat Boom Boom until after we built My Little Roguelike.

We did not want to make the same mistakes this time and agreed to add the networking as early as was feasible. Also, the server will be based on websockets, even for Android and Destkop, so that the HTML5 client can connect to it.

Today we began writing what will hopefully become the server and it uses the headless backend of libGDX. It is mostly the same as the desktop backend but does not initialize the video and sound subsystems, and has only a console; ideal for servers applications.

The only caveat in not having a graphics subsystem is that you can not create textures: it throws a NullPointerException when it tries to use the OpenGL context to generate the texture. This is usually not a problem because it is not necessary, nor useful, to load textures in a standalone server application and we can just skip that step, but we had an issue when loading Tiled maps.

The placeholder circuit was made using Tiled with two layers, one layer with the position of the tiles and the second with polyline objects that define the collision shapes, that is the circuit’s barriers. The client needs both layers, because it renders the circuit on screen and uses the collision data to perform the same physics simulation as the server and anticipate all movements, while the server only needs to load the collision layer. However, we were unable to find a way to load only the object layer using libGDX’s TmxMapLoader; it will always load the tileset layer and create the required texture for the tiles, therefore emiting a NullPointerException every time.

At the end we had to create a new class, say ServerMapLoader, that overides the load method in a way that prevents the creation of textures. Please note that it still requires that the ImageResolver returns a non-null TextureRegion, even though it is strictly speaking not necessary.

public class ServerMapLoader extends TmxMapLoader {
    @Override
    public TiledMap load(String fileName, Parameters parameter) {
        FileHandle tmxFile = resolve(fileName);
        this.root = xml.parse(tmxFile);

        TiledMap map = loadTiledMap(tmxFile, parameter, new ImageResolver() {
            @Override
            public TextureRegion getImage(String name) {
                return new TextureRegion();
            }
        });
        return map;
    }
}