Moving a character around the map 2 – Movement and Orientation


Code for this tutorial is on this git branch:

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

Have a look here for help setting it up


If you have got the project up and running, you should be looking at a character moving around the screen when you click.

ZombieGamePlayerOnScreen

If you can not get the project to run, post a message at the bottom and we’ll sort it out.

PlayerCharacter

The PlayerCharacter is where we have our logic which deals with orientation and movement. We also draw our sprite here – it draws itself to a SpriteBatch when requested.

Movement and orientation is all done with vector logic, using Libgdx’s built-in Vector2 class.

When we set up the PlayerCharacter, we give him a random start position. The code to pick a random spot is quite straightforward for now – anywhere on the map which is classed as land.

Every time the PlayerCharacter’s update() method is called, the player will see whether a destination has been set, see if we are already at the destination, and if not – move towards it and point at it.

Movement

When we click in the PlayerInputSystem, we pass a tile to the PlayerCharacter to set as the destination. We also do this:

diff = destination.asVector().cpy();
diff.sub(pos);

diff is of type Vector2. diff is now a Vector2 representing the vector between the destination and the player’s current position.

Note: we’ve added a method to our Pair class, to convert it to a Vector2.

Next, we update(). First we check that we actually have a destination (if you haven’t clicked yet, it will be null!). Then we check that we aren’t already standing at the destination (or close to it). If either of these things are the case, we do nothing.

Assuming we want to update our position, we do this:

diff.setLength(PLAYER_SPEED);
pos.add(diff);

diff is still a vector pointing in the same direction as before, but with a fixed length (whatever you set PLAYER_SPEED as – try playing with it to see the effect). Our position is also a vector, so we add this ‘diff’ vector to our current position, and it gives us a new vector which is an addition of the two.

Vector addition
A visual representation of adding some vectors. Think of A, B and C as the results of 3 different clicks

Orientation

Ok, we have updated our position. Now for the orientation. All we do is work out the angle between two vectors (our position and destination):

private void updateOrientation() {
   float angle = (float) Math.toDegrees(Math.atan2(destination.x - pos.x, destination.y - pos.y));
   this.orientation = - angle + 90f;
}

Why did we add that +90f at the end? It is just to correct for the player image looking the wrong way. If you just updated the actual image to be pointing another 90 degrees round, you would get the same effect. I probably could have done that in the time in took me to write this explanation…

That’s it! You’ve updated the orientation and position variables. Now, when we are told to draw the player, we have all the information necessary.

public void draw(GameController game, SpriteBatch batch) {
   playerSprite.setCenter(pos.x, pos.y);
   playerSprite.setOrigin(1, 1);
   playerSprite.setRotation(orientation);
   playerSprite.draw(batch);
}

We’re walking on water!

Yes we are. This is the most basic implementation of movement I could put in for now; we don’t even check whether we can proceed without touching water. Once we’ve moved on to later tutorials, we’ll actually be doing path-finding each time we touch somewhere. We will abandon this approach – naively move in a straight line – and the player will walk around bodies of water!

If you fancy a challenge now, and to improve your understanding of how things tie together, why don’t you stop the player from being able to walk on water? It doesn’t require any path-finding.

We’re going to use path-finding instead. So is this logic useless to us?

No! A feature will we add in a few tutorials is to fire bullets at zombies. This logic will be used for that – sprites moving in a straight direction, able to move over land or water – perfect for bullets.

Conclusion

We’ve taken a look at vector logic for moving in straight directions, and orienting sprites to ‘look at’ what we want them to look at.

Next up:

  • Determining which tile we have just touched
  • Having a camera track the player


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.

Moving a character around the map


Code for this tutorial is on this git branch:

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

Have a look here for help setting it up


Up until now we have generated a random map, and got a camera pointing at it. Now, we move to something more interesting – moving a character around a map.

ZombieGamePlayerOnScreen2

This tutorial is the second time we will download a pre-existing project that I have added to git. It’s the same project that you checked out earlier (assuming you’ve followed along this tutorial), but a different branch.

With this code, you will be able to do the following:

  • Place a character on our map
  • Click somewhere else on the map and have the character travel towards where you clicked
  • Track the character’s movement with the camera

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

Check out the branch with the command above. We’re not going to go over every code change, but we’ll look at the core stuff.

The flow of logic

  • GameController creates a player character
  • PlayerInputSystem detects a TouchDown event (a click on a computer, a touch on a touchscreen). Determine what coordinate on the screen was touched. Tells the player to treat this coordinate as its destination
  • GameController update() method is called, in turn calls the update() method of PlayerCharacter
  • PlayerCharacter compares its current position, its destination, and updates its orientation and position
  • GameScreenRenderer draws the map (as it was doing before) and draws the player
  • Repeat!

Getting graphics

man

I’ve provided an image to use for our character, but I didn’t create it. I took it from here:

http://opengameart.org/content/animated-top-down-survivor-player

So all credit for the image goes to ‘rileygombart’, who has made his/her graphics available. These kind of websites are a great source of graphics if you are artistically challenged (as we are – graphics for Dinowar were done by a friend).

I’ve added this graphic to the project and called it ‘man’.

Remember the tutorial on Texture Packing? Well, we will need to rebuild out atlases to include this. Then later we just ask for ‘man’ from the TextureAtlas. If you’re running the project as it is, this should happen automatically when you run the code.

ZombieGamePlayerOnScreen

Hopefully you are seeing something like this when you run the code! If not, do get in touch.

Try clicking around to see how the player sprite behaves. Next up, we’ll go into more detail about the new code.

 



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.

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.