Chronicles of a Videogame in Java – 4. Building a tiled map

Previously on the Chronicles of a Videogame in Java: How to Make the Character Jump.

Here we are again ladies and gentlemen! Today we’re going to see how to build a tiled map for our still not so beautiful platform game. But first, let’s see what a tiled map is and especially what a single tile is.

There’s not a one-way definition of “tile”, as the term applies to both data structures and images. Let’s look at this picture to understand the concept:

tiledMap

Ok, the entire grid you see in the screenshot above it’s called a tiled map. The tiled map for this game has 9 rows and 20 columns for a total of 180 cells that will contain single static elements of the game. Here’s an example: the red square in the picture above contains a piece of terrain, so it is infact a static element of the game because it is placed there forever. From a logic kind of perspective then, that piece of terrain is a tile placed in the 7th row and 7th column of the tiled map. Pretty easy uh?

What do we place in a tiled map? Usually just terrain, blocks on which you may jump, spikes, maybe doors and other static elements. Don’t be misleaded by the image above though, the trees you see behind the characters are not part of the tiled map, contrariwise that’s just a background image. We have basically three layers in the world of the picture:

  1. The first and stupidest thing is the background. It is just a plain png image we draw on the background of the panel where the game is played. It does not involve interactions with the player whatsoever.background1
  2. The second layer you see is the one with the terrain tiles. Here’s now how the image above looks like if we add the tiled map with all the tiles (for now just terrain pieces). The terrain tiles do involve an interaction, for example the character can walk on terrain tiles and collide running towards them. terraintiles
  3. The last things are the characters and enemies moving on the world. They do not need to stay inside the tiled map of course, indeed I would say it is hugely inconvenient do put the main character inside a tiled map. Our protagonist just needs to be drawn above the other layers and the class representing him in the code should always reference the position of the character inside the tiled map (in terms of row and col).terraintiles

Now let’s put it all to code. First the Tile class, which is an abstract class as we do not want to istantiate a generic Tile, but rather specific types of tiles that behave in different ways.

public abstract class Tile {
	public Tile(int i, int j){
		this.row=i;
		this.col=j;
		initializeStuff();
	}
	
	protected abstract void initializeStuff();
	
	protected abstract void loadInformations();
	
	public BufferedImage getImage(){
		return image;
	}
	
	public Rectangle getBoundingBox() {
		return boundingBox;
	}
	
	protected int row;
	protected int col;
	protected BufferedImage image;
	protected Rectangle boundingBox;
	public static final int TILE_SIZE=64;
}

The piece of terrain we discussed earlier is a Block object in the code. The Block class extends Tile: you can think of a block as any piece of material you can walk on and collide with. Its bounding box occupies the entire perimeter of a cell in the tiled map grid.

public class Block extends Tile {

	public Block(String imgName,int i, int j) {
		super(i,j);
		this.imgName=imgName;
		loadInformations();
	}

	@Override
	protected void initializeStuff() {
		x=col*TILE_SIZE;
		y=row*TILE_SIZE;
		boundingBox=new Rectangle(x,y,TILE_SIZE,TILE_SIZE);
	}
	
	protected void loadInformations() {
		try {
			image=ImageIO.read(getClass().getResource("../images/"+imgName+".png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private String imgName;
	private int x;
	private int y;
}

All the tiles of the current stage are stored in the bidimensional array named “tiledMap” in the World class. As you may notice the tiledMap is public, that’s because there’s no need to hide informations about the world as you see it and, even more important, it is really convenient to be able to grab te tiled Map from anywhere in the code. The world class actually loads the current disposition of tiles from a simple text file.

public class World {
	public World(){
		tiledMap=new Tile[ROWS][COLS];
	}
	
	public void initializeStage(String stageName){
		try {
			CURRENT_BACKGROUND=ImageIO.read(getClass().getResource("../images/background1.png"));
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		InputStream is=this.getClass().getResourceAsStream("/levels/"+stageName+".txt");
		BufferedReader reader=new BufferedReader(new InputStreamReader(is));
		String line=null;
		String[] tilesInLine=new String[ROWS];
		try {
			int i=0;
			while((line=reader.readLine())!=null){
				tilesInLine=line.split(" ");
				for(int j=0; j<COLS; j++){
					if(!tilesInLine[j].equalsIgnoreCase("empt")){
						tiledMap[i][j]=newTileInstance(tilesInLine[j],i,j);
					} else {
						tiledMap[i][j]=null;
					}
				}
				i++;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private Tile newTileInstance(String name, int i, int j) {
		switch (name) {
			case "ter0":
				return new Block("ter0", i, j);
			case "ter1":
				return new Block("ter1", i, j);
			case "terR":
				return new Block("terR", i, j);
			case "terL":
				return new Block("terL", i, j);
			case "terQ":
				return new Block("terQ", i, j);
			case "terP":
				return new Block("terP", i, j);
			case "term":
				return new Block("term", i, j);
		}
		return null;
	}

	public static BufferedImage CURRENT_BACKGROUND;
	public static Tile[][] tiledMap;
	public static final int ROWS=9;
	public static final int COLS=20;
}

Finally here’s what the .txt representation of a level looks like:

empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt
empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt
empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt
empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt
empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt
empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt
empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt empt
ter0 ter1 ter0 ter1 ter0 ter1 ter0 ter1 terR empt terL ter1 ter0 ter1 ter0 ter1 ter0 ter1 ter0 ter1
term term term term term term term term terQ empt terP term term term term term term term term term

Yep, I know I know. It looks barely readable. But if you look closely and you relate this text to the first picture of the post you’ll notice the parts with no terrain tiles (or tiles of any sort) are represented by the “empt” keyword and the several types of terrain tiles are “ter0” or “ter1” or ter+something_else.

Aaaaaaand that would be all for today. I’m sorry for this very theoretical post but the tiled-map one is really a concept you want to fully understand before you go on and code the funny things. Once again, remember that this is not a proper tutorial, but just a “how I make things” kind of thing. So if you have suggestions or you don’t understand what I say, please comment below or get in touch with me on twitter. I’m also on tumblr, drawing stuff.

In the next episode…we will die!

Advertisements
Chronicles of a Videogame in Java – 4. Building a tiled map

3 thoughts on “Chronicles of a Videogame in Java – 4. Building a tiled map

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s