Search Unity

Tilemap: Associating more properties to every tile on map.

Discussion in '2D' started by Aviian, Jul 13, 2018.

  1. Aviian

    Aviian

    Joined:
    Jul 13, 2017
    Posts:
    1
    I like how Unity has provided a Tilemap and Tile palette but I don't like how difficult it seems to add my own properties to each and every tile. In fact, I've only come across a single tutorial that covers this (after looking at quite a lot of websites) located here. They did not take the scriptable tile route (subclassing TileBase) that everywhere else suggests.

    Problem 1 (Likely solved by link above): I need to add more properties associated with a tile for things like movement cost floats for pathfinding algorithms. The scriptable tile examples essentially get you to create prefabs and they look geared to only performing this on a handful of tiles where I need every single tile to have these properties. What is the best way to do this with the Tilemap system? Should I go the route of the posted link and create a dictionary that associates a position with a class (no inheritance)?

    Problem 2: For pathfinding, I need an efficient method of assigning movement cost values to possibly hundreds of tiles at one script location and not on a tile by tile basis. Nobody wants to assign/modify hundreds of tiles by hand. I've figured out a possible method but would like more insight on other methods.

    I'm an experienced programmer, but not in C# so bear with me. I take criticism well. My current thoughts for a method would be to follow the link above and create a dictionary of Vector3Int positions as key and the following class from that page as values (modified to my use of course):

    Code (CSharp):
    1. public class WorldTile {
    2.     public Vector3Int LocalPlace { get; set; }
    3.     public Vector3 WorldLocation { get; set; }
    4.     public TileBase TileBase { get; set; }
    5.     public Tilemap TilemapMember { get; set; }
    6.     public string Name { get; set; }
    7.  
    8.     // Below is needed for Breadth First Searching
    9.     public bool IsExplored { get; set; }
    10.     public WorldTile ExploredFrom { get; set; }
    11.     public int Cost { get; set; }
    12. }
    Then create an Enum that describes tile types:

    Code (CSharp):
    1. enum TileTypes { Grass, Rock, Water}; // and so on
    These tile types need to have a movement cost associated with them so somewhere I'll need to probably create a dictionary to act as a lookup using the TileTypes enum:

    Code (CSharp):
    1. public Dictionary<TileType, float> moveCostLookup;
    Now this is where I get lost. How do I associate potentially hundreds of sprites to a single enum so that I only have to change the value in one place (moveCostLookup dictionary) and not on a tile by tile basis? The only thing I could think of is to use a list of lists containing sprites. the lists would be in the same order as the enum so list[0] would be the list of grass sprites, list[1] would be the list of rock sprites, etc. Then on initialization, as I loop through all the tiles painted on the tilemap, loop through this list of lists to see if any of them contain the sprite, use the index of the list that holds it to look up the moveCostLookup. An untested attempt at code for this explanation:

    Code (CSharp):
    1. // Loop through each tile in tilemap and get sprite
    2. Vector3Int pos; // determine based on loop above
    3. Sprite sp = tileMap.GetSprite( pos );
    4.  
    5. foreach(List<Sprite> spriteTypeList in spriteLists){
    6.     if ( spriteTypeList.Contains(sp) ){
    7.         int index = spriteLists.IndexOf(spriteTypeList);
    8.         float cost = moveCostLookup[index];
    9.         // Do stuff with cost float
    10.     }
    11. }

    Any suggestions would be greatly appreciated. I would like the end product to be potentially functional on mobile so efficiency is highly desired.
     
  2. RidgeWare

    RidgeWare

    Joined:
    Apr 12, 2018
    Posts:
    67
    Another way is to create some 2-dimensional arrays which can store data for each x/y coordinate. Very simple to set up, and you don't have to create thousands of instances of WorldTiles.

    On Awake you can just populate the arrays based on the tilemap info (like setting the cost based on the tile name for example, etc). And then just look in the array whenever a check for tile cost is needed.
     
  3. rakkarage

    rakkarage

    Joined:
    Feb 3, 2014
    Posts:
    683
    Code (CSharp):
    1. public int TileIndex(int x, int y)
    2. {
    3.     return y * Width + x;
    4. }
    5. public Vector2 TilePosition(int index)
    6. {
    7.     var y = index / Width;
    8.     var x = index - Width * y;
    9.     return new Vector2(x, y);
    10. }