Tile Maps (Static)

This is part 1 of a series of articles about programming techniques for Tile Map engines, commonly used in 2D video games.

Complex maps have multiple layers, scrolling, animations, isometric views, etc. Before we get to the advanced maps, we need to begin with the simplest map possible.

In this lesson we'll render a Chess board. Here's how we want the final view to appear:

Chess board with pieces

We have several data elements that go into this scene:

  • The blank chessboard background image ("Background")
  • The images for individual chess pieces ("Tile Set")
  • A 2D array holding the current chess piece positions ("Tile Map")

The Background

Blank Chessboard
Here's our blank chess board. We could render it from dark/light tiles, but for this lesson we'll use a whole image. Our chess board in this example is 256x256 pixels, with each tile being 16x16.


Image board = new Image("chessboard.png");

The Tile Set

Chess pieces (tile set)
Here I'm using a .gif with a transparent background. Each piece fits comfortably into a 16x16 tile.

To build the Tile Set, we first we enumerate what can exist in any one space on a chess board:


enum Piece {
  empty_space,
  white_pawn,
  white_rook,
  white_knight,
  white_bishop,
  white_queen,
  white_king,
  black_pawn,
  black_rook,
  black_knight,
  black_bishop,
  black_queen,
  black_king
};

Next, we load our tile set into an image array:


Image[] tile_set = new Image[13];

// Copy/Load the white pawn image into tile_set[Piece.white_pawn]
// etc.

The Tile Map

We'll store the current state of the game board in a 2D array.


Piece[][] tile_map = new Piece[8][8];

We'll use this array as tile_map[column][row], with the top-left corner being [0][0]. We can assign the starting board positions:


// setup the game board
tile_map[0][0] = Piece.white_rook;
tile_map[1][0] = Piece.white_knight;
tile_map[2][0] = Piece.white_bishop;
...
tile_map[0][2] = Piece.empty_space;
...
// etc

The Render

To redraw the current scene, we take the following steps:

  • Draw the blank chess board over the previous screen
  • Loop through all rows/columns of the chess board
    • If this slot isn't empty (no chess piece) ...
    • Determine the (x,y) screen location of this chess piece
    • Draw the chess piece onto the screen at that location

Here's the code:


void render() {

  // screen (x,y) is the pixel position on the screen to draw a game piece
  int screen_x;
  int screen_y;
  
  // assuming a library function:
  // void draw(Image src, Image dest, int dest_x, int dest_y);
  
  // draw the blank chess board
  draw(board, screen, 0, 0);
  
  // loop through the chess spaces and draw any pieces
  for (int row=0; row<8; row++) {
    screen_y = row * 16; // 16 = tile pixel height  
    
    for (int column=0; column<8; column++) {
      screen_x = column * 16; // 16 = tile pixel width

      if (tile_map[column][row] != Piece.empty_space) {
        draw(tile_set[tile_map[column][row]], screen, screen_x, screen_y);
      }
    }
  }
  
} // end render();

This two-dimensional render loop is common to almost all tile map engines, and is fairly easy to understand. In the next article, we'll look at how to scroll the viewscreen around a large game map.