Se você deseja criar terrenos destrutíveis, a maneira como fiz isso no Unity é colocar apenas coletores nos limites do seu mundo. Então, por exemplo, é isso que você gostaria de realizar:
Todos esses blocos verdes contêm um colisor e o restante não. Isso economiza muito em cálculos. Se você destruir um bloco, poderá ativar os colisores em blocos adjacentes com bastante facilidade. Lembre-se de que ativar / desativar um colisor é caro e deve ser feito com moderação.
Portanto, o recurso Tile é assim:
É um objeto de jogo padrão, mas também pode ser agrupado. Observe também que o colisor de caixa está definido para ser desativado por padrão. Somente ativaríamos se for um bloco de borda.
Se você está carregando estaticamente seu mundo, não há necessidade de juntar seus ladrilhos. Você pode carregar todos eles de uma só vez, calcular a distância da borda e aplicar um colisor, se necessário.
Se você estiver carregando dinamicamente, é melhor usar um pool de blocos. Aqui está um exemplo editado do meu loop de atualização. Carrega blocos com base na visualização atual da câmera:
public void Refresh(Rect view)
{
//Each Tile in the world uses 1 Unity Unit
//Based on the passed in Rect, we calc the start and end X/Y values of the tiles presently on screen
int startx = view.x < 0 ? (int)(view.x + (-view.x % (1)) - 1) : (int)(view.x - (view.x % (1)));
int starty = view.y < 0 ? (int)(view.y + (-view.y % (1)) - 1) : (int)(view.y - (view.y % (1)));
int endx = startx + (int)(view.width);
int endy = starty - (int)(view.height);
int width = endx - startx;
int height = starty - endy;
//Create a disposable hashset to store the tiles that are currently in view
HashSet<Tile> InCurrentView = new HashSet<Tile>();
//Loop through all the visible tiles
for (int i = startx; i <= endx; i += 1)
{
for (int j = starty; j >= endy; j -= 1)
{
int x = i - startx;
int y = starty - j;
if (j > 0 && j < Height)
{
//Get Tile (I wrap my world, that is why I have this mod here)
Tile tile = Blocks[Helper.mod(i, Width), j];
//Add tile to the current view
InCurrentView.Add(tile);
//Load tile if needed
if (!tile.Blank)
{
if (!LoadedTiles.Contains(tile))
{
if (TilePool.AvailableCount > 0)
{
//Grab a tile from the pool
Pool<PoolableGameObject>.Node node = TilePool.Get();
//Disable the collider if we are not at the edge
if (tile.EdgeDistance != 1)
node.Item.GO.GetComponent<BoxCollider2D>().enabled = false;
//Update tile rendering details
node.Item.Set(tile, new Vector2(i, j), DirtSprites[tile.TextureID], tile.Collidable, tile.Blank);
tile.PoolableGameObject = node;
node.Item.Refresh(tile);
//Tile is now loaded, add to LoadedTiles hashset
LoadedTiles.Add(tile);
//if Tile is edge block, then we enable the collider
if (tile.Collidable && tile.EdgeDistance == 1)
node.Item.GO.GetComponent<BoxCollider2D>().enabled = true;
}
}
}
}
}
}
//Get a list of tiles that are no longer in the view
HashSet<Tile> ToRemove = new HashSet<Tile>();
foreach (Tile tile in LoadedTiles)
{
if (!InCurrentView.Contains(tile))
{
ToRemove.Add(tile);
}
}
//Return these tiles to the Pool
//this would be the simplest form of cleanup -- Ideally you would do this based on the distance of the tile from the viewport
foreach (Tile tile in ToRemove)
{
LoadedTiles.Remove(tile);
tile.PoolableGameObject.Item.GO.GetComponent<BoxCollider2D>().enabled = false;
tile.PoolableGameObject.Item.GO.transform.position = new Vector2(Int32.MinValue, Int32.MinValue);
TilePool.Return(tile.PoolableGameObject);
}
LastView = view;
}
Idealmente, eu escreveria um post muito mais detalhado, pois há muito mais nos bastidores. No entanto, isso pode ajudá-lo. Se houver perguntas, não hesite em perguntar ou entrar em contato comigo.