TextureAtlas and TexturePacker


Code for this tutorial is on this git branch:

git clone -b Base_project https://dglencross@bitbucket.org/dglencross/zombiegametutorial.git

Have a look here for help setting it up


So far in this tutorial, we have a drawn a map. We’ve gone in to detail about how we’ve created the data structure that is the map layout, but we haven’t spoken much about the mechanics of how we store and display the actual graphics. This might seem a bit straightforward for the map (it is just a single tile drawn repeatedly), but when we start introducing moving characters (next tutorial after this one!) it will be more important.

early_map
Quite clear from this image – the same square tile drawn repeatedly to make up the map
feature_graphic
The tiles aren’t quite so obvious here, but each one is a different type of tile – for example, a corner tile, a side tile. Each dinosaur is also a sprite which makes use of a texture from an atlas

If you are at all familiar with 2-D game programming, you’ll probably be familiar with the concept of sprites and that each one has an image (or texture) that is what you see represents the sprite.

What is a TextureAtlas?

Think of it as one large image which you load into memory. This image is all your other images stuck together, side-by-side, in one large ‘texture’ (or a subset of them). Then, there is an accompanying json file (formatted text) which tells a program where each individual image is. So it will say e.g. top-left for 50px width, 50px height is an image called ‘zombie’. Then when I ask for the texture called ‘zombie’, I’ll get back just the relevant part of the overall image.

Why use a TextureAtlas rather than a bunch of individual images?

Check out the wikipedia article for a good description:

https://en.wikipedia.org/wiki/Texture_atlas

but basically – faster memory usage. As well as this, the atlas makes it very easy to deal with your graphics. Drop an image in a folder, re-build your atlas, and then ask for it by name.

Here’s a bit of code from Dinowar:

String spriteName = "Dinosaur__"+ fromBase.getOwner().getPlayerColor().name() +" Air";
Sprite sprite = gameController.getMainScreen().getMainAtlas().createSprite(spriteName);

We are creating a sprite directly from the atlas. createSprite(String name) is a built-in Libgdx method.

Building the TextureAtlas with the TexturePacker

How to create our atlas though? It would not be a time-saver if you had to create the json file and giant image yourself. This is where the TexturePacker comes in. We referred earlier to some unused code in the DesktopLauncher:

if (packTextures) {
   TexturePacker.process(settings, assets_general + "images", assets_android + "atlas", "main");
   settings.duplicatePadding = true;
   TexturePacker.process(settings, assets_general + "tiles", assets_android + "atlas", "tiles");
}

We’re building two atlases here. We’re specifying where the files we want to pack are with the second parameter:

assets_general + "images"

We’re specifying where to save the atlas with the third parameter:

assets_android + "atlas"

And we’re naming our atlas with the fourth parameter:

"main"

At the moment, this code section is not running because we have set packTextures to false. Why don’t you try changing it to true and running it?

Check the console, and you should see output like this:

images
Packing………
Writing 512×1024: atlas/main.png
tiles
Packing………
Writing 1024×512: atlas/tiles.png
127 74

Let’s check out file locations. For me on a Mac, these are:

Original files – /Users/dave/git/zombiegametutorial/assets_general/images

Created Atlas – /Users/dave/git/zombiegametutorial/android/assets

And the folder we’ve written out to now contains these files:

atlas files

Let’s take a look inside the tiles.atlas:tiles.atlas

It refers to the image name, some metadata about the image, and then lays out the different texture areas – in our case, there is just one, called “white”.

We’ve packaged our graphics up for use in our Android game – change it to iOS if you’re creating your iOS version of the game.

Note: we usually keep packTextures to false because we don’t need to create these atlases every time – just when we’ve made changes.

Creating the Atlas object in game

In MainScreen.java, we’ve got this method, called from the constructor:

private void setUpGraphics() {
// Set up graphics here for passing between classes
// Try to keep everything here to make for easy disposal at the end.
tilesAtlas = new TextureAtlas("atlas/tiles.atlas");
Tile.setSprites(tilesAtlas);
}

So we’re already set up with our atlas! Have a look in Tile.java to see what is going on.

public static void setSprites(TextureAtlas tiles) {
   plainTile = tiles.createSprite("white");
   
   // Make sure we do this, it then does it for the whole atlas.
   plainTile.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
}

We create our sprite, and later when the draw() method is called, we’ll draw it on to the screen. This occurs when our GameScreenRenderer has its update() method called, and it in turn tells each Tile to draw itself.

Conclusion

We’ve seen how to pack a collection of images into an atlas, and how to then reference that atlas to draw sprites on the screen.

These tile sprites aren’t very interesting though – they’re just a white square! In our next tutorial, we’ll get a character moving around the screen, and so we’ll be using an atlas for this – you’ll find though, that the principles are exactly the same as the tiles that we have drawn here.



If you like these tutorials, or want to see a game that was written in much the same way, please download Dinowar from the Google Play Store. It costs nothing and is ad-free.

Leave a Reply

Your email address will not be published. Required fields are marked *