- Home /
Tiles map data structure
Hello Unity community. I recently started getting familiar with Unity and 2d games. There is tons of information all over internet, but i haven't found a full answer to one question..
Let's say i want to create a tile map 50x50 (100x100?) tiles, where each tile is a sprite. I want to be able to load map from file and dynamically build it in runtime.
What is the best data structure for a tile? GameObject with SpriteRenderer? And whole map is a just an array of gameobjects?
Is it a memory/cpu optimal solution, or there is something better?
Are there any general recommendations on how to properly maintain many objects like tiles in memory and reuse them properly?
I will be really grateful for help and answers.
Cheers.
Answer by Eric5h5 · Feb 03, 2014 at 03:54 AM
It's simplest/fastest to use an array to represent the level. In the simplest case, if you have
If you have a limited number of tiles, you can instantiate them all at once. For larger levels, though, that's not a great idea, since e.g. 100x100 = 10,000 separate objects, which is a strain on Unity. Even though only a relatively few might appear on-screen, they all have to be culled every frame, which is a waste of CPU cycles, not to mention RAM. So you can instantiate only as many as you need and use a pooling system to recycle them as the camera moves.
Erick5h5, hi. Thanks for your response. But how would you render a 100x100 tile map on the screen? What would you use for rendering a tile?
Thanks!
With that many tiles visible at once, it would be better to use the $$anonymous$$esh class to construct a combined mesh by setting vertices (and other properties such as UVs) through code.
Answer by iwaldrop · Feb 03, 2014 at 02:31 AM
The best data structure is something that maximizes data capacity while minimizing storage space requirements. This will make for faster de/serialization, and will minimize the memory footprint during runtime. A basic structure might look like this.
[System.Serializable] public class Map { public Tile[] tiles; }
[System.Serializable] public class Tile { public enum Type { Grass, Sand, Water }
public Type type; public Embellishment embellishment; } [System.Serializable] public class Embellishment { public enum Type { City, Tower, Ruins } public Type type; }
It would be easy to either subclass embellishment instead of using an enum, or to instantiate the proper prefab based on it.
It is a fact of life when dealing with tiles that the data behind them needs to be in RAM while they're being used. There are some solutions out there that are constantly de/serializing each tile as they are panned on/off screen, but with computers these days this is seldom necessary. CPU wise, you're only talking whatever overhead each tile needs. I.e. they have some sort of update loop running. If they are constantly calculating things, think about throttling via coroutines.
There are several 'pool managers' out there which help to make spawning many copies of the same thing less computationally expensive. Instantiating and Destroying objects are very expensive, and the less of that you can do during game-play the better. Many of these solutions spawn several copies up-front (at load-time) and allow them to be simply moved to the proper position and enabled when they're needed.
iwaldrop, thank you for your detailed response. But still i do not understand, what is the most efficient way of rendering a tile? For each possible tile type to create a prefab and clone it(creating gameobjects)? How would you render a map of 100x100 tiles? Pool managers look great, but I have a strategy game and most of the time, 70-80% of all tiles are on the screen, and even with zoom, i cannot remove/spawn tiles all the time, because in case of fast scrolling user will probably notice appearing tiles. So please, could you give me some info on how to render 100x100 tiles map on the screen in the most sufficient way?
Thanks so much!
As Eric mentions below, creating a mesh and manipulating it at runtime is probably the most efficient solution for actually drawing the tiles. You'd likely only want to pool whatever will be occupying the tiles and, because your game is realtime, leave the units active at all times. Disabling the mesh renderer when the unit is slightly off screen will help with renderer culling, because the only active rendererers will be onscreen or just slightly off. Finally, use LOD and low definition models to remove verts while zoomed out to keep the fps high.
Answer by Fabkins · Feb 03, 2014 at 06:10 PM
I needed to do something similar to what you need and pretty much as Eric's described.
I store the tiles in a simple array:
var metaMap = new MetaMapObj[100,100];
I'm using a simple file format of "Tile:23:54:34" where the parameters x,y,tile type. The load script is very straight forward (this one is not robust).
function LoadMap(filepathIncludingFileName : String)
{
var sr = new File.OpenText(filepathIncludingFileName);
var input = "";
while (true)
{
input = sr.ReadLine();
if (input == null) { break; }
var paramaters = input.Split(":"[0]);
switch( paramaters[0])
{
case "Tile":
var x: int=System.Int32.Parse(paramaters[1]);
var y: int=System.Int32.Parse(paramaters[2]);
var i: int=System.Int32.Parse(paramaters[3]);
SetInternalMap(x,y,i);
break;
case "Building":
/* Add some more data types */
break;
}
}
sr.Close();
}
SetInternalMap() essentially just does "metaMap[x,y].tileType=i;"
I then created a custom mesh. This is not the for feignt hearted though as you need to understand what vertices, normals, UV and triangles are for. One word of advice, dont bother trying to re-use the vertices as it makes the code much much simpler.
NOTE: I originally created tiles using objects, this was very slow in on workstation (5 secs?). Creating the mesh and loading the files is super fast.
One word of warning though, if you are constantly changing tiles, this will be slow because you have to replace the UV map for the WHOLE mesh, you cant replace just the part of the mesh you want. Consequently, I cash the UV map, make however many changes I need, then replace the UV map.
Using OBJECTS: Pro: fast change of tiles , easy to code CON: Long initial load times
Using MESH: Pro: fast creation/load time, CON: slow change of tiles
Your answer
Follow this Question
Related Questions
How do I get my tiles to overlap my Background sprite? 2D 1 Answer
[Tilemap] Can you spawn a Prefab (with colliter) together with a tile when placing it? 0 Answers
2D Animation does not start 1 Answer
Texture grid displayed oddly when width =/= height 1 Answer
Pathfinding solutions for 2D Dungeon Keeper style game 3 Answers