Я немного пробовал новую TileMap
систему в Unity и искал способ доступа к плиткам в виде списка или 2D-массива, но я не могу найти ничего, кроме того, GetTile(Vector3Int vector)
что возвращает только одну плитку ... Есть ли способ сделать это ?
Чтобы получить массив со всеми плитками из прямоугольной области вашей карты тайлов, используйте 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()
.Вот еще один способ сделать это с .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);
}
Во время выяснения, как получить все пользовательские листы из Tilemap, и из-за метода ITilemap
has, 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)
но я не проверял это.
GetComponent<Tilemap>()
.