Storing map data (tiles) in a dictionary?

Started by
6 comments, last by FFA702 4 years, 5 months ago

So I'm working on a hobby project using C# in Unity. For the purpose of this thread, the game is basically XCOM: its a tactical, turn based, square grid based game. The game is in 3D.

 

I have build a simple map editor, that allows me to place prefab 'tile' game objects, that contain a 'Tile' component. When a map is loaded, all the tiles are collected by a map manager script, initialized, and stored in a Dictionary<Vector2Int, Tile>, where the Vector2Int consists of the tile's x and y coordinate and the Tile is a reference to the tile component. Since I only use the x and y position, I cannot create caves or buildings with multiple floors (i.e. two tiles with the same x and y but different z coordinates), but this is I accept. As for the map size, I want to be able to use maps with up to some 1000 tiles.

 

Using this dictionary, I implemented pathfinding, and it allows me to easily look up / interact with any specific tiles (and their content). Also, the map can automatically have any shape (e.g.irregular edges, can contain holes, etc.), which is nice.

 

My question: is a dictionary a sensible way to store and access map (tile) data? Are there any drawbacks or potential problems I can run into later? Is there a compelling reason to use another structure such as a 2D array, where I will have to write custom 'TryGetValue' like methods, etc.?

 

Tell me what you think!

Advertisement

A 2D array would probably be more memory-efficient and faster, with better cache locality, for almost all maps that you would actually use.  I can think of corner cases where a dictionary is more memory-efficient, but they require that over 90% of your 2D array is empty.

I'd say it depends on what you do with the data. If it is just for static storage then an array may be best. If you have to look up or search tiles, a sorted data structure is an option. If you need the spatial data to determine which tiles to show,  for lod-ing or to accelerate drawing, a spatial databstructure like an octree Edit: quadtree i mean - is a possible way ...

Always seen it done with arrays.

There are a couple of cool syntax things you can do.


public class Map
{
  private Tile[,] tiles;
  public Tile this[int x, int y] => tiles[x, y];
  public Map(int xSize, int zSize)
  {
  	tiles = new Tile[xSize, zSize];
  }
}

You can declare a dimensional array using commas inside the square brackets.

And you can overload the square brackets operator for a class by using "this[]" as a getter.

That allows you to use the instances of Map as if it was an array of Tiles

If you really wanted to you could do a conditional in the getter to handle indexes out of bounds.


public Tile this[int x, int y] => x < 0 || x >= tiles.GetLength(0) || y < 0 || y >= tiles.GetLength(1) ? null : tiles[x, y];

If you were looking for a dynamic sized tile map, generally the approach is to use a list of chunks.

Usually the only time you'd choose a Dictionary for a tile map is if the grid is mostly empty.  In other words, if you only have three integer keys: 1, 5000, and 160000, using that key as an index into an array would require an array at least 160001 entries long, with the majority filled with unused null or default values.  That's where a dictionary will work better.  But if your keys are 0, 1, 2, 3, 4, 5, 6, then the dictionary has unnecessary overhead and the array should be used instead.

7 hours ago, Comrad S said:

Since I only use the x and y position, I cannot create caves or buildings with multiple floors (i.e. two tiles with the same x and y but different z coordinates), but this is I accept.

As long as you don't tell or show the player x, y, or z, sure you can. Add a way to teleport the player not to the cell next door, but to an entirely different position. There, make the supposedly z+1 level room, and at the other end, teleport the player back to wherever he is supposed to arrive from the supposedly room level.

As long as you keep things consistent, the player will believe he went to z+1 and back.

 

7 hours ago, Comrad S said:

is a dictionary a sensible way to store and access map (tile) data? Are there any drawbacks or potential problems I can run into later?

As said already, a dictionary carries a lot of overhead in accessing, not to mention the space used by all the (x,y) vectors (one for every tile). So be aware it's likely not the most efficient way to store the information.

On the other hand, as long as you don't have a problem with it, just keep it, and work on things that need to be added, or are broken and need fixing. You don't aim for "perfect", aim for "working sufficiently well". That makes faster progress in writing the game.

1000 tiles is trivial for C#. If the code behave as intended, I wouldn't touch it. However it seems overengineered to me.

This topic is closed to new replies.

Advertisement