Nếu bạn đang tìm cách tạo địa hình có thể phá hủy, cách tôi đã làm trong Unity, là chỉ đặt máy va chạm trên các khối cạnh của thế giới của bạn. Vì vậy, ví dụ, đây là những gì bạn muốn thực hiện:
Tất cả những khối màu xanh lá cây này đều có máy va chạm và phần còn lại thì không. Điều đó tiết kiệm một tấn trên các tính toán. Nếu bạn phá hủy một khối, bạn có thể kích hoạt các máy va chạm trên các khối liền kề khá dễ dàng. Hãy nhớ rằng kích hoạt / hủy kích hoạt máy va chạm là tốn kém và nên được thực hiện một cách tiết kiệm.
Vì vậy, tài nguyên Ngói trông như thế này:
Nó là một gameobject tiêu chuẩn, nhưng nó cũng có thể sử dụng được. Cũng lưu ý rằng trình tạo hộp được đặt thành bị tắt theo mặc định. Chúng tôi sẽ chỉ kích hoạt nếu nó là một gạch cạnh.
Nếu bạn đang tải tĩnh thế giới của mình, không cần phải gộp các ô của bạn. Bạn chỉ có thể tải tất cả chúng trong một lần bắn, tính khoảng cách của chúng từ cạnh và áp dụng máy va chạm nếu cần.
Nếu bạn đang tải động, tốt nhất là sử dụng một nhóm gạch. Đây là một ví dụ chỉnh sửa của vòng lặp làm mới của tôi. Nó tải gạch dựa trên chế độ xem camera hiện tại:
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;
}
Lý tưởng nhất là tôi sẽ viết một bài chi tiết hơn nhiều, vì có khá nhiều điều đang diễn ra đằng sau hậu trường. Tuy nhiên, điều này có thể giúp bạn ra ngoài. Nếu có câu hỏi hãy hỏi hoặc liên hệ với tôi.