Se stai cercando di creare un terreno distruttibile, il modo in cui l'ho fatto in Unity è quello di mettere i collider solo sui bordi del tuo mondo. Quindi, ad esempio, questo è ciò che vorresti realizzare:
Tutti quei blocchi verdi contengono un collider e il resto no. Ciò consente di risparmiare un sacco di calcoli. Se distruggi un blocco, puoi attivare i collider su blocchi adiacenti abbastanza facilmente. Tieni presente che l'attivazione / disattivazione di un collider è costosa e deve essere eseguita con parsimonia.
Quindi, la risorsa Tile si presenta così:
È un oggetto di gioco standard, ma è anche raggruppabile. Si noti inoltre che il box collider è disabilitato per impostazione predefinita. Attiveremmo solo se si tratta di una tessera bordo.
Se stai caricando staticamente il tuo mondo, non è necessario unire le tue tessere. Puoi semplicemente caricarli tutti in un colpo, calcolare la loro distanza dal bordo e applicare un collider, se necessario.
Se si carica dinamicamente, è meglio usare un pool di tessere. Ecco un esempio modificato del mio ciclo di aggiornamento. Carica le tessere in base alla vista corrente della videocamera:
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, scriverei un post molto più dettagliato, dato che c'è molto altro dietro le quinte. Tuttavia, questo può aiutarti. Se ci sono domande, sentiti libero di chiedere o contattarmi.