James Williams
LinkedInMastodonGithub

Using Sprite Sheets with PlayN

Tags: HTML5 Gaming

In a previous blog post, I detailed a port of a sprite packing application from desktop Java to HTML5 using Chrome packaged apps. Now we'll create some PlayN object to use the assets the packer creates.

Data Format

Each sprite sheet archive contains two files: an image containing all the sprites and a JSON definitions file. The JSON file contains information about the contained sprites including their filenames, upper-left coordinate in the sheet, and the sprite's height and width. Below is a sample definitions file.

[
  {"name":"1_club.png","x":0,"y":0,"width":169,"height":245},
  {"name":"1_diamond.png","x":170,"y":0,"width":169,"height":245},
  {"name":"5_diamond.png","x":340,"y":0,"width":169,"height":245}
]

Putting it all together

In my app, I created a PlayN handler class to lead the sprite sheet and programmatically separate it into sub-images. AssetWatcher allows us to execute a function done on load completion.

public CardSpriteSheet(String filename) {
  this.filename = filename;
  this.assetWatcher = new AssetWatcher(this);
  this.image = assets().getImage(filename);
  this.assetWatcher.add(this.image);

  assets().getText(filename+".def", this);
  this.assetWatcher.start();
}

Here we can see how the sub-images get created after load.

public void done() {
  try {
    objects = new HashMap<String, Image>();
    for (int i = 0; i<definitionList.length(); i++) {
      JSONObject obj = definitionList.getJSONObject(i);
      Image region = image.subImage(
        obj.getInt("x"), 
        obj.getInt("y"), 
        obj.getInt("width"), 
        obj.getInt("height")
      );
      objects.put(obj.getString("name"), region);
    }
  } catch(JSONException ex) {}
}

Moving from loading individual files to sprite sheets greatly reduces application startup time.

Check out the source code here.