Tilemapping – Generating Isometric and Hexagonal Tilemaps.

When planning and designing for a strategy game, you as a developer must focus on how much freedom you allow your players to have. Strategy games are a genre that is defined by a ruleset that rewards good decision making and problem solving. A decision can be made over the mundane to the monumental and it is your job, as a developer, to recognise and compensate smart play.

We utilise tile based systems as a means of storing groups of information within a limited space (both literally and for hardware storage purposes). Tile mapping is an efficient method of generating vast game spaces with limited art assets due to the repeated use of each tile and was originally a solution used when hardware limitations wouldn’t meet the demands of audiences asking for “bigger games”.

Rogue was released in 1980 and used a tile-based coordinate system so players could count exactly how far away objects and enemies were from the player.

A dictating feature that adds the complexity of the genre is the design of the environments in which the decision making takes place. A traditional square-based tile system provides the user with a possible 5 options regarding their adjacent movement and positioning, move in one of 4 directions past the edges of the square or leave a unit on the tile they currently occupy. Strategy and war games made the transition to utilising hexagonal tiles with the main benefit being that the distance from the centre of one tile to another would always be the same unlike square-based maps in which the distance is actually longer across diagonal neighbouring square tiles than the distance between adjacent tiles.

Demonstrating how movement along a hexagonal based system can prove useful when accounting for consistent tactical movement. Cubic Tiling is less convincing when moving diagonally due to the incosistency of distance between tiles.

Modify the square-based tiles to tesselating Heaxgonal tiles and the possibilities jump from 4 to 6 potential options that a player has to consider per tile (Or you can use square tiles for 8 potential movement directions accounting for diagonal movements, therefore limiting the options). Hexagonal tiles also simulate more realised movements as they can account for diagonal movements and thus open up a larger pool of options to consider.

The increase in options adds for further processing on behalf of the player when making decisions.

When programming a game for the incorporation of tiles the main point to consider is the configuration of vertecies to avoid any spaces. To produce a standard hexagonal tesselation pattern, you would need an understanding of the internal angle of a hexagon is 120 degrees. The hexagon is made up of 6 equilateral trianges with 60 degree angles inside. A hexagon has a width = sqrt(3) * size and a height = 2 * size. To prevent the shapes from overlapping we have to calculate the distance between the centres of each adjacent hexagon. Horizotal being the width and the vertical being height * 3/4. 

When working with Tile-based systems, it is always good practice to know how the shapes can fit together and what techniques should be attempted in order to index each tile created.

When using non-cubic tiling methods, its very much a “take your own approach” problem to solve. My preferred method due to its simplicity is to offset the coordinates of each tile so we only have to focus on the x and y axis. This is done by adding an offset to each tile in an odd or even row/column. A quick and easy fix!

The code snippet below iterates through and places hexagons and calculates an offset value so that they connect (it is also possible to use this function to create gaps between each tile  by adding a value to the width and height variables before calculating the offset). I also give each tile generated a name to their corresponding position in the tilemap so I can later index them to be called individually by name if needed and .

void CalcStartPos()
{
   float offset = 0;
   if (gridHeight / 2 % 2 != 0)
   {
    offset = hexWidth / 2;
    float x = -hexWidth * (gridWidth / 2) - offset;
    float z = hexHeight * 0.75f * (gridHeight / 2);
    startPos = new Vector3(x, 0, z);
    }
}

Vector3 CalcWorldPos(Vector2 gridPos)
{
    float offset = 0;
    if (gridPos.y % 2 != 0)
        offset = hexWidth / 2;

    float x = startPos.x + gridPos.x * hexWidth + offset;
    float z = startPos.z - gridPos.y * hexHeight * 0.75f;

    return new Vector3(x, 0, z);
}

void CreateGrid()
{
    for (int y = 0; y < gridHeight; y++)
    {
        for (int x = 0; x < gridWidth; x++)
        {
            Transform hex = Instantiate(hexPrefab) as Transform;
            Vector2 gridPos = new Vector2(x, y);

            hex.position = CalcWorldPos(gridPos);
            hex.parent = this.transform;
            hex.name = "Hexagon" + x + "|" + y;
        }
    }
}

In order to create a coordinate system, each tile should contain a location or position on a map that we can convert to pixel measurements for accurate positioning of resources. We can round pixel measurements for use in non-cubic coordinates by converting our own system to cubic units and performing any rounding needed before converting the coordinates back to our own units.

Hexagonal tiles can be given coordinates corresponding to their faces, edges and verticies. In the context of games, faces provide the most simplistic and broadest range of applications since they are easy to read and can be tiled in the same way standard cubic maps are.

And that just about concludes this short introduction to tilemap generation. I will provide some sources for additional reading that I found helpful when approaching this problem. Tilemaps provide so much flexibility to a project and are a really solid way of keeping track of objects and representing areas of play! 

https://www.redblobgames.com/grids/hexagons/

http://www.gamasutra.com/blogs/HermanTulleken/20140912/225495/20_Fun_Grid_Facts_Hex_Grids.php