简体   繁体   中英

Unity 2D Tile Map — Group Tiles By Type C#

I'm looking for a solution to group my games tiles by the type of tile they are. The tiles are stored in a 2d array and have the types empty and water, the tiles that are group will be stored in a Group class.

So if I have the 2d array:

0, 0, 0, 0, 0, 0, 0, 0,

0, 1, 1, 1, 0, 0, 0, 0,

0, 1, 1, 0, 0, 0, 1, 1,

0, 1, 0, 0, 0, 0, 1, 1

where 0's are empty and 1's are water there would be two water groups.

I have spent all afternoon trying to figure it out, here is what i have at the moment.

public void GenerateGroups(){
    //Debug.Log("Generate Groups");
    m_Groups = new List<Group>();
    List<Tile> groupingTiles = new List<Tile>();

    int groupId = 1;

    foreach(Tile t in m_Tiles){
        t.IsGrouped = false;
    }

    for(int y = 0;  y < Height; y++){
        for (int x = 0; x < Width; x++) {
            Tile tile = m_Tiles[x, y];

            if(tile.Type == TileType.Water && !tile.IsGrouped){

        //      if(m_Tiles[x+1, y].IsGrouped || m_Tiles[x, y + 1].IsGrouped){
        //          if(m_Groups.Count > 0){
        //              foreach(Group g in m_Groups){
        //                  if(g.m_Tiles.Contains(m_Tiles[x+1, y]) || g.m_Tiles.Contains(m_Tiles[x, y + 1])){
        //                      g.m_Tiles.Add(tile);
        //                      tile.IsGrouped = true;
        //                      continue;
        //                  }
        //              }
        //          }
        //      }else{
        //          groupingTiles.Add(tile);    
        //      }

                groupingTiles.Add(tile);

                tile.IsGrouped = true;

                Tile next = m_Tiles[x + 1, y];
                int pos = x + 1;

                while(next.Type == TileType.Water && !next.IsGrouped && pos < Width){
                //  Debug.Log("Going right!");
                    groupingTiles.Add(next);
                    pos++;
                    next.IsGrouped = true;
                    next = m_Tiles[pos, y];
                }

                next = m_Tiles[x, y + 1];
                pos = y + 1;

                while(next.Type == TileType.Water && !next.IsGrouped && pos < Height){
                    //Debug.Log("Going up!");
                    groupingTiles.Add(next);
                    pos++;
                    next.IsGrouped = true;
                    next = m_Tiles[x, pos];
                }

            }

            if(groupingTiles.Count > 0){
                //Debug.Log("Group Tiles: " + groupingTiles.Count);
                m_Groups.Add(new Group("Group_" + groupId, groupingTiles));
                groupId++;
                groupingTiles = new List<Tile>();
            }
        }
    }


    Debug.Log(m_Groups.Count);
}

Any help would be appreciated thanks!

I would approach this by saving a reference of the group inside the tile. When encountering a water tile, check if either it's left or bottom neighbour is also a water tile. This could end in four cases:

  1. neither left or bottom are water tiles (or exist): create a new group on the current one
  2. left / bottom is a water tile: add current to the group of left / bottom
  3. both left and bottom are water tiles in the same group: add current to their group
  4. both left and bottom are water tiles in a different group: now the groups have a connection and need to be merged. also add current to that new group

I wrote a piece of code as a demonstration, but note that it is untested and simplified. I think the merging of two groups is kind of a hassle, since you have the update the reference of each of it's tile. Also, you have to sort out the groups with just one tile later (if needed). But it should point you in the right direction:

for(int y = 0; y < Height; y++)
{
    for(int x = 0; x < Width; x++)
    {
        Tile currentTile = GetTile(x, y);

        if(!currentTile.IsWater)
            continue;

        Tile leftTile = GetLeftNeighbour(currentTile);
        Tile bottomTile = GetBottomNeighbour(currentTile);

        if(!leftTile.IsWater && !bottomTile.IsWater)
        {
            //first case
            Group newGroup = new Group();

            newGroup.Tiles.Add(currentTile);
            currentTile.Group = newGroup;                
        }
        else if(leftTile.IsWater && !bottomTile.IsWater)
        {
            //second case A
            leftTile.Group.Tiles.Add(currentTile);
            currentTile.Group = leftTile.Group;
        }
        else if(!leftTile.IsWater && bottomTile.IsWater)
        {
            //second case B
            bottomTile.Group.Tiles.Add(currentTile);
            currentTile.Group = bottomTile.Group;
        }
        else
        {
            if(leftTile.Group == bottomTile.Group)
            {
                //third case
                leftTile.Group.Tiles.Add(currentTile);
                currentTile.Group = leftTile.Group;
            }
            else
            {
                //fourth case
                leftTile.Group.Merge(bottomTile.Group);

                leftTile.Group.Tiles.Add(currentTile);
                currentTile.Group = leftTile.Group;
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM