Skip to main content

Use your data

Now that everything is set up, using data cells is as easy as adding and saving a reference to the TilemapExtended controller script. gstThis section is meant to give an example of how data can be accessed and modified along with some useful grid utilities.

Adding TilemapExtended

A common architectural pattern found in Unity is to organize scripts in a hierarchical relationship using manager or controller MonoBehaviours. In this example, a GameController MonoBehaviour script will be used at the top level in which we will reference TilemapExtended, which itself is organized with such a controller called TilemapExtended.

Head to the main TilemapExtended asset folder and drag the TilemapExtended prefab into the scene hierarchy:

adding TilemapExtended prefab

Since we kept the default grid name 'Grid', hit the Detect button in the TilemapExtended inspector to auto-add references to the Grid and Tilemap objects which are needed internally. If you renamed the grid game object to something else, drag them into the inspector by hand alternatively.

Remember to hit Detect again anytime you add or delete new Tilemaps or entire grids.

Finally, drag the TilemapRules object created earlier into the TileRules field and the inspector should look something like this:

final TilemapExtended prefab

Accessing TilemapExtended

In terms of TilemapExtended everything is now ready and set up, so everything following now is meant as a brief example of how this tool could be used. To add a new controller script, create a new C# script named 'GameController' which will automatically create a MonoBehaviour template. Add an empty game object to the scene and attach the newly created script.

To use (almost) anything related to TilemapExtended, a reference to the TilemapExtended game object is needed. The one exception are the static grid utility methods which you can use if you aren't interested in data storage.

Remember that anything that comes with this tool is contained in the TExtended namespace. The controller script could look something like this:

using UnityEngine;
using TExtended;

//The reference to the TilemapExtended script (not the game object containing it)
public TilemapExtended TilemapExtended;

void Awake() {}

void Start() {
//Find the TilemapExtended game object containing the TilemapExtended script
var tilemapExtendedObject = GameObject.Find("TilemapExtended");
//Add the script reference from the game object to our public property
tilemapExtended = tilemapExtendedObject.GetComponent<TilemapExtended>();
}

void Update() {}

So far we're only referencing TilemapExtended but aren't doing anything with it so let's look over some use cases.

Accessing cell data

Let's expand the newly created GameController script by logging the TileType over which the mouse hovers the console. This will mainly take place in the Update method:

using UnityEngine;
using TExtended;

//References the main camera
private Camera _camera;

public TilemapExtended TilemapExtended;

void Awake() {}

void Start() {
//Gets the main camera
_camera = GameObject.Find("Main Camera").GetComponent<Camera>();

var tilemapExtendedObject = GameObject.Find("TilemapExtended");
tilemapExtended = tilemapExtendedObject.GetComponent<TilemapExtended>();
}

void Update() {
//Gets the mouse position and converts the screen point to a world coordinates
var mousePosition = _camera.ScreenToWorldPoint(Input.mousePosition);
//Important - the z-component in the vector needs to be zero to get the correct position
mousePosition.Set(mousePosition.x, mousePosition.y, 0.0f)
//Converts the mouse world position to a grid position
var gridPosition = TilemapExtended.GridExtended.GetNearestCellPosition(mousePosition);

//Gets the cell data at the mouse grid position
//Important - since we extended CellData with our own properties, cast CellData to MyCellData
//The data store will always return the CellData base class!
var cell = TilemapExtended.DataCells.GetCell(gridPosition) as MyCellData;
//Logs the terrain type enum to the console
if (cell != null) Debug.Log(cell.terrainType);
}

In short, data access is handled in a single line of code. Just remember to cast the returned CellData base class to your custom data class like in the code above.

Once you have access to data cells, modifying data is just as simple since every cell is an individual instance of the data object you created:

var gridPosition = new Vector3Int(1, 4, 0);
var cell = TilemapExtended.DataCells.GetCell(gridPosition) as MyCellData;

//Increases the movement cost from 1 (default) to 2 if TileType is Grass
if (cell.terrainType == TerrainType.Grass) {
cell.movementCost = 2;
}

Getting neighbours

TilemapExtended is more than just cell data storage. Equally as useful to quickstart your projects are the provided grid utility methods. Lets say we have a player that can perform certain actions depending on the tile and the tiles around the player. In order to implement this, we need to check the neighbouring tiles. In a rectangular grid this is pretty simple, however, in a hex grid this would be more difficult.

basic neighbours

TilemapExtended provides this and a ton more of these useful methods via the GridExtended class contained inside TilemapExtended:

var gridPosition = new Vector3Int(1, 2, 0);

//Returns a list of neighbouring cells
var neighbours = TilemapExtended.GridExtended.GetNeighbours(gridPosition);

//Iterate neighbour cells to check for TerrainType
foreach (var neighbour in neighbours) {
var neighbourData = neighbour as MyCellData;

if (neighbourData.terrainType == TerrainType.Ocean) {
//Add fishing to list of actions
}
}

Because GridExtended knows the grid type in use (rectangular in this case), the same call to GridExtended.GetNeighbours will return the correct implementation of GetNeighbours in a hex grid without needing to change or manually specify anything.

Getting a path

This tool provides basic pathfinding based on an implementation of the A* algorithm with a custom MinHeap data structure. Basic pathfinding data is already implemented in CellData and therefore available to all data cells:

modified grass data

Get a shortest path from one valid position (if position has cell data stored) to another by calling Pathfinder:

var playerPosition = new Vector3Int(0, 0, 0);
var target = new Vector3Int(5, 2, 0);

//Creates a shortest path between the player and the target
var path = tilemapExtended.Pathfinder.GetPath(playerPosition, target);

foreach (var point in path) {
//Do something with path
}

Adding data cells at runtime

If you want to modify your tilemaps at runtime by adding or removing tiles, CellDataStore needs to be updated. If the new tile is part of the TilemapRules container you can simply call AddCell:

var newTilePosition = new Vector3Int(3, 1, 0);

//Scans the tile position and adds the correct data cell if possible
TilemapExtended.DataCells.AddCell(newTilePosition);

Removing or replacing cells based on tilemap changes works exactly the same. Just remember to update data cells if tilemaps are changed at runtime.