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.

Generating random maps


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


This game isn’t going to have fixed ‘levels’ – each time you play a new random map will be created. This is exactly how our released game Dinowar works. We even let the user regenerate the maps until they find one they are interested in playing – the maps generate in a fraction of a second.

If you are interested to see how quickly it generates on a mobile device, download the game and have a play (if you are on Android).

Every time the player clicks the ‘refresh’ button on the right hand side, the following happens:

  • New map is generated
  • Bases are allocated (notice the lighter purple border lines)
  • Paths are generated between each base
  • The player and AI players are created and each allocated a base, depending on difficulty level.

For the Zombie game we are creating in this tutorial series, we will be looking at the first of those – creating a random map.

Representing a map in code

Our maps are rectangles, with a width and a height, and is basically broken up into lots of little cells. This might start to sound familiar…

2dArray

This is a 2-dimensional array, and the highlighted field can be referenced with map[5][8].

Now imagine if you filled this array with 1s and 0s. 0s can represent water, and 1s can represent land. Or you could fill it with any numbers you want – 0s can represent water, 1s represent coastlines, 10s represent mountainous regions, 2-9 represents somewhere in between the two extremes. Then when you draw your map, whenever you see a 10 you draw a mountain colour and so on.

In fact, early versions of Dinowar did exactly that:

early_map

Very different from the first screenshot in this post! But the core mechanics behind it are the same.


An aside: why did we choose to go with more simple maps, rather than ones with gradients? In the end, the biggest factor was speed of path-finding. Our path-finding uses Jump Point Search, an adaptation of A* search algorithms, which is faster but loses the ability to take into account different gradations of node – each node is either passable or it is not, unlike a graded map where it might be ‘expensive’ to cross a mountain.


So, all you need is a 2-D array of ints – this is a simple structure to work with. Have a look in World. We have written our own wrapper class for an int, so that we can add additional functionality to it – the ability to tell a node to draw itself, the ability to ask if it is land or water. This might seem a little pointless at the moment, but further down the line we will find it easier to work with than ints. But we have still got the 2-D array declared in World:

protected Pair[][] map

Now all you need to do is decide which Pairs should be water, and which should be land.

Noise

What you want is an algorithm which you can pass some desired width/height parameters and get back an array filled with noise. As mentioned above, we want this to be fast. There are a few different choices of algorithm that we researched, but settled on Simplex Noise. Simplex Noise is computationally cheap compared to other algorithms. For more information read the wiki:

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

In the best spirit of open-source software development, we are going to use code someone else wrote so that we don’t have to get too bogged down in the detail. This code comes from Richard Tingle on Stack Overflow, who in turn used code in the public domain from Stefan Gustavson.

http://stackoverflow.com/questions/18279456/any-simplex-noise-tutorials-or-resources

I’m not going to repeat his lesson here – if you are interested in the technical detail of how it works, read the answer on Stack Overflow.

Simplex Noise works well for maps because it has a continuous gradient throughout, so you can get ‘blocks’ of land.

We also have to provide this algorithm with some frequencies and amplitudes (again, read Stack Overflow for details) so that it has some random ‘seeds’ to work from. This logic is in WorldGenerator, take a look at the generateMap method.

You’ve essentially got hold of an array of noise, of the correct size for your map. Each time you call it, you pass in some differently generated freqs and amps, and get back a 2-D array full of floats.

The final stage to get your actual map data is to convert these floats into ints of 0 or 1, representing land/water. In our case, every Pair (or node) represents either water or land. We have set a threshold (still in WorldGenerator) – anything below this threshold is water, anything above it (or equal to it) is land. Try fiddling with this threshold if you want to increase/decrease the amount of water.


Aside: if you do want to have proper detail on your maps (with mountains etc), check out this excellent tutorial here: http://javagamexyz.blogspot.co.uk/2013/03/terrain-generation.html

The idea is the same, you just have various thresholds for different levels of land instead of only one.


There you have it! An 2-D array which looks like a not-too-terrible representation of a 2-D map.

All that’s left is to draw it.

Rendering the map

Open up the GameScreenRenderer and take a look at the only thing it is drawing. It makes use of a SpriteBatch (which we’ll come to in a tutorial more focused on graphics).

We loop over the Pairs in the map, and tell each one to draw itself. Each Pair holds a reference to its own Sprite, which in this case is just a white square which we will set the colour of to either blue or green depending on whether it is water or land. This might seem like overkill for drawing coloured squares – but when you want to do more complicated stuff (in Dinowar, some of the tiles are borders and have to draw different images), this is very handy.

And there you have it!

Screen Shot 2016-07-17 at 15.17.31
A map generated with Simplex Noise

Update!

I’ve written a new tutorial, where you can make your maps look a lot nicer. Check it out here: http://tutorials.boondog.xyz/2017/02/19/prettier-maps/



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.

Project structure


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


We have the standard Libgdx projects, with all the code/logic being in the ‘core’ project, which then has wrappers – in our case, Desktop and Android. The other available options (we you can add yourself if needed) are for iOS and HTML5. If you are following this tutorial to make an iOS game don’t worry – it’s all still relevant.

N.B. I’m going to break down the structure of our project a bit, if you aren’t interested (or you would rather just work it out as you go), then you can skip over this tutorial without worrying about it.

DesktopLauncher

You should have already run the DesktopLauncher and successfully run the game. The code is just a wrapper, with a little additional logic for setup.

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");
}

This code gives you a hint of a future tutorial – atlases. This is the way we do graphics – pack our graphics into an atlas, then load this atlas when we want to load images in the game.

This code snippet does not run currently, because packTextures is set to false. We also aren’t loading anything from atlases in game – yet. We’ll come back to it.

Core project

The core project is where all of our in-game code is going to be. Anything specific to Android/iOS should live in those respective projects (e.g. achievements) – anything they all have in common should be in core.

You may have noticed in the DesktopLauncher that we created a new instance of MainScreen and passed it to new ‘application’ we’ve created.

MainScreen

Here we set up our InputProcessor (PlayerInputSystem), our Stage and our Renderer (GameScreenRenderer). We also have more references to our graphics atlas – again, we’ll come back to that in a later tutorial (when we start adding some graphical elements to our game). We also have a GameController where we will keep logic for what is going on in the game. For example, we will control our zombies from here.

Input Processor – PlayerInputSystem

This is where we respond to key-presses, screen touches, the back button being pressed etc. If you have a look, you can see that you implement the InputProcessor interface, and add logic to any of the methods that you want to capture.

Renderer – GameScreenRenderer

This is where we draw all our graphics. Libgdx will keep calling the render method in our MainScreen, and from there we call the update method in our GameScreenRenderer to make sure all graphics are updated.

GameController

This is pretty bare at the moment, but we’re going to have any logic which needs running in here. For example, loop through all our zombies, work out which should be moving, work out where they should move to – this can all be controlled from within the update method, which will be called by the MainScreen every time render is triggered by the game engine.

It’s the interaction of these three elements which run the core of our game, updating logic, updating graphics, and responding to commands from the player.

The rest of it we’ll work out as we go. Notice that we’ve structured the packages of the core project to try and separate things into their logical components.

Next time we will take a closer look at one of these logical components – the map generating functionality.



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.

Setting up the project

The first few tutorials will work like this: we’ll provide you a sample project, and explain the various aspects of how it works.

From there, we’ll guide you through building new features and enhancements on to the game.

Dependencies

We have written a little helper project, which you can find at https://github.com/dgmp88/MyGdxClasses. It contains a template layout for setting up a Libgdx application, as well as various utility functions.

We install this via gradle, which you will need on your machine. Once you have got that, run the following commands:

git clone https://github.com/dgmp88/MyGdxClasses
cd MyGdxClasses
gradle install

Getting the source code

We are assuming you’re familiar with Git. To directly check out the example project, run the following command:

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

This checks out a specific branch for just the Base_project – in future we’ll check out different branches to see different examples.

Android Studio

We created this tutorial in Android Studio, and all examples are going to assume that is your IDE, but in reality most stuff should be the same with other IDEs. This may vary when it comes to exporting the project to Android or iOS.

We’re assuming you have Java set up properly on your machine – this tutorial isn’t going to cover that.

Once you’ve checked out the code and opened Android Studio, choose ‘Open an Existing Android Studio project’ and locate the project.

Run configurations

Start the game by opening the file ‘Desktop Launcher’ and Run. This will probably fail first time, but that’s just because we haven’t set up the run configuration yet. Click the down arrow next to ‘DesktopLauncher’ to open it up.

Screen Shot 2016-07-09 at 18.37.38

Make sure you have the following settings:

Main class: com.boondog.games.desktop.DesktopLauncher

Working directory:[path]/zombiegametutorial/android/assets/

(for example, on my Mac the path is /Users/dave/git/zombiegametutorial/android/assets/)

Use classpath of module: Desktop

Now try running the game again. If all has been set up correctly, you should see something which looks a bit like this:

Screen Shot 2016-07-09 at 18.41.33

If you see this – success!

What am I looking at?

This is the base project, which is just a randomly-generated map. At the moment, there’s not much you can do here. Try navigating around with the arrow keys, try zooming in and out with the Z and X keys.

Also – try pressing R to regenerate the map. Neat eh?

Why does it look so crap?

We haven’t provided any logic for drawing edges properly, so it looks quite blocky at the moment. You can decrease the ‘blockiness’ by changing a couple of parameters.

Open up ZombieGame.java and look for:

float viewWidth =32;

Try changing the value to something bigger, and you can see the effect. Have a play around with the other variables in there and see what happens. You can make it look like this:

Screen Shot 2016-07-09 at 18.51.59

Why wouldn’t you just make it really high-definition? Well, further down the line we’re going to introduce some path-finding. Each block on the map is a node, and the higher number of nodes, the slower it is going to be to generate paths. This is a real issue we came across when creating Dinowar, so we had to find a balance between the detail of the map and the speed of path-finding on a mobile device.

But in the end, you can make the map look a lot better by drawing edges properly:



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.

Creating a 2-D Zombie shooter

The game that we are going to create in this tutorial is a top-down, 2-D shooter. Like Dinowar, it will feature randomly generated maps. The idea is for the player to spawn at a random point on the map, and have to make their way to another point on the map.

In the way of the player will be a number of zombies. When the player gets within a certain range of a zombie, that zombie will run at the player. We can choose to have the zombies run only in a straight line, or we can choose to have them run around things in the way (e.g. water).

The player character will always be central in the screen, and the camera will follow them. When the user touches somewhere on the screen, the player character will walk to that spot.

When zombies run at the player, the user can touch a zombie to fire a bullet at it. If the bullet hits, the zombie dies. If the zombie touches the player, the player loses health.

Screen Shot 2016-07-09 at 18.21.20

Sounds simple? Then move on to the next post to get started.



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.

Welcome to our new Libgdx Tutorials

Approximately a year ago, we (Dave and George) were big fans of an Android game called Archipelago. This was a simple game in which a player controls islands, and sends planes from island to island to capture more. The player had to fight against 2-4 AI players, with the objective being to control the map.

The two of us decided that this game could be improved upon, and as we both come from a technical background and both enjoy programming, we would have a stab at it.

We settled on Libgdx as the right framework for our needs, and set about creating the game. The main reasons it took so long were (in no particular order) our inability to focus on one project at a time, our jobs, and our struggles to make the game actually look nice.

But we have finally (a couple of months ago now) released Dinowar for Android, written with Libgdx:

googleplay

We’ve now decided to write some Libgdx tutorials in order to help others who might be interested in writing a similar game. Throughout this tutorial series, we will write a game which features a lot of the same gameplay as Dinowar, while trying to avoid adding unnecessary complexity. Some of the features of this series will be topics that we had to research and implement during our time developing Dinowar:

  • Random map generation
  • Efficient path-finding
  • Creating in-game tutorials
  • Rendering fonts
  • Creating and using atlases for graphics
  • Using Overlays for GUIs
  • Adding achievements and leaderboards
  • Developing AI which is engaging to play against