Jeśli chcesz stworzyć zniszczalny teren, tak jak ja to zrobiłem w Unity, ustawianie zderzaków tylko na skrajnych blokach twojego świata. Na przykład to, co chciałbyś osiągnąć:
Wszystkie te zielone bloki zawierają zderzak, a reszta nie. To oszczędza mnóstwo obliczeń. Jeśli zniszczysz blok, możesz dość łatwo aktywować zderzaki na sąsiednich blokach. Pamiętaj, że aktywacja / dezaktywacja zderzaka jest kosztowna i powinna być wykonywana oszczędnie.
Zasób kafelków wygląda następująco:
Jest to standardowy obiekt gry, ale można go również pulować. Zauważ również, że moduł zderzający jest domyślnie wyłączony. Aktywowalibyśmy się tylko, jeśli jest to kafelek krawędzi.
Jeśli ładujesz swój świat statycznie, nie ma potrzeby łączenia płytek. Możesz po prostu załadować je wszystkie w jednym ujęciu, obliczyć ich odległość od krawędzi i w razie potrzeby zastosować zderzak.
Jeśli ładujesz się dynamicznie, najlepiej użyć puli kafelków. Oto edytowany przykład mojej pętli odświeżania. Ładuje kafelki na podstawie bieżącego widoku kamery:
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;
}
Idealnie napisałbym o wiele bardziej szczegółowy post, ponieważ za kulisami dzieje się o wiele więcej. Może ci to jednak pomóc. W razie pytań możesz zapytać lub skontaktować się ze mną.