Как получить все плитки из Tilemap?

13

Я немного пробовал новую TileMapсистему в Unity и искал способ доступа к плиткам в виде списка или 2D-массива, но я не могу найти ничего, кроме того, GetTile(Vector3Int vector)что возвращает только одну плитку ... Есть ли способ сделать это ?

Shashimee
источник

Ответы:

18

Чтобы получить массив со всеми плитками из прямоугольной области вашей карты тайлов, используйте tilemap.GetTilesBlock(BoundsInt bounds). Вы получите одномерный массив плиток, поэтому вам нужно знать, когда начинается следующий ряд плиток. Любые пустые ячейки будут представлены nullзначением.

Если вы хотите все плитки, используйте tilemap.cellBounds. Это дает вам BoundsIntобъект, который покрывает всю используемую область тайла карты. Вот пример сценария, который получает все плитки из Tilemap для одного игрового объекта и перечисляет плитки с их координатами:

using UnityEngine;
using UnityEngine.Tilemaps;

public class TileTest : MonoBehaviour {
    void Start () {
        Tilemap tilemap = GetComponent<Tilemap>();

        BoundsInt bounds = tilemap.cellBounds;
        TileBase[] allTiles = tilemap.GetTilesBlock(bounds);

        for (int x = 0; x < bounds.size.x; x++) {
            for (int y = 0; y < bounds.size.y; y++) {
                TileBase tile = allTiles[x + y * bounds.size.x];
                if (tile != null) {
                    Debug.Log("x:" + x + " y:" + y + " tile:" + tile.name);
                } else {
                    Debug.Log("x:" + x + " y:" + y + " tile: (null)");
                }
            }
        }        
    }   
}

Что касается границ и того, почему вы можете получить больше плиток, чем вы ожидаете: Концептуально, Unity Tilemaps имеют неограниченный размер. cellBoundsРасти по мере необходимости , когда вы рисуете плитки, но они не дают усадку снова , если вы удалите их. Так что, когда ваша игра имеет четко определенный размер карты, вы можете получить некоторые сюрпризы, если вы когда-нибудь промахнетесь при редактировании карт. Есть три способа обойти эту проблему:

  • Позвоните, tilemap.CompressBounds()чтобы восстановить границы для крайних плиток (надеясь, что вы помните, чтобы стереть их)
  • создать boundsобъект самостоятельно, new BoundsInt(origin, size)а не полагаться на cellBounds.
  • установить tilemap.originи tilemap.sizeна желаемые значения, а затем вызвать tilemap.ResizeBounds().
Philipp
источник
11

Вот еще один способ сделать это с .cellBounds.allPositionsWithin

public Tilemap tilemap;
public List<Vector3> tileWorldLocations;

// Use this for initialization
void Start () {
    tileWorldLocations = new List<Vector3>();

    foreach (var pos in tilemap.cellBounds.allPositionsWithin)
    {   
        Vector3Int localPlace = new Vector3Int(pos.x, pos.y, pos.z);
        Vector3 place = tilemap.CellToWorld(localPlace);
        if (tilemap.HasTile(localPlace))
        {
            tileWorldLocations.Add(place);
        }
    }

    print(tileWorldLocations);
}
allencoded
источник
2

Во время выяснения, как получить все пользовательские листы из Tilemap, и из-за метода ITilemaphas, GetTilesBlockкоторый упоминался в ответах, я предлагаю добавить такой метод расширения (только для 2D):

public static class TilemapExtensions
{
    public static T[] GetTiles<T>(this Tilemap tilemap) where T : TileBase
    {
        List<T> tiles = new List<T>();

        for (int y = tilemap.origin.y; y < (tilemap.origin.y + tilemap.size.y); y++)
        {
            for (int x = tilemap.origin.x; x < (tilemap.origin.x + tilemap.size.x); x++)
            {
                T tile = tilemap.GetTile<T>(new Vector3Int(x, y, 0));
                if (tile != null)
                {
                    tiles.Add(tile);
                }
            }
        }
        return tiles.ToArray();
    }
}

В этом случае, если у вас есть, предположим, пользовательская плитка TileRoad, унаследованная от Tile или TileBase, то вы можете получить все плитки TileRoad с помощью вызова:

TileBase[] = tilemap.GetTiles<RoadTile>();

Для ITilemap мы можем изменить параметр (this Tilemap tilemap)на, (this ITilemap tilemap)но я не проверял это.

Дмитрий Табаков
источник
В какой ситуации вам нужно работать с интерфейсом ITilemap? Я не сталкивался с этим вообще во время моих экспериментов с системой Tilemap. Я всегда приобретал компонент Tilemap с GetComponent<Tilemap>().
Филипп
Филипп, ничего не могу сказать об интерфейсе, потому что я тоже работал только с Компонентом.
Дмитрий Табаков