Si estás buscando crear un terreno destructible, la forma en que lo hice en Unity es solo colocar colisionadores en los bloques de borde de tu mundo. Entonces, por ejemplo, esto es lo que le gustaría lograr:
Todos esos bloques verdes contienen un colisionador, y el resto no. Eso ahorra una tonelada en cálculos. Si destruye un bloque, puede activar los colisionadores en bloques adyacentes con bastante facilidad. Tenga en cuenta que activar / desactivar un colisionador es costoso y debe hacerse con moderación.
Entonces, el recurso Tile se ve así:
Es un objeto de juego estándar, pero también se puede agrupar. Observe también que el colisionador de cuadros está configurado para deshabilitarse de manera predeterminada. Solo se activaría si se trata de un mosaico de borde.
Si está cargando estáticamente su mundo, no hay necesidad de agrupar sus fichas. Puede cargarlos todos de una sola vez, calcular su distancia desde el borde y aplicar un colisionador si es necesario.
Si está cargando dinámicamente, es mejor usar un grupo de mosaicos. Aquí hay un ejemplo editado de mi ciclo de actualización. Carga mosaicos basados en la vista actual de la cámara:
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, escribiría una publicación mucho más detallada, ya que hay bastante más detrás de escena. Sin embargo, esto puede ayudarte. Si hay preguntas, no dude en preguntarme o contactarme.