正如標題所說,我想知道如何阻止預制件重疊?
這是我當前的代碼
{
List<GameObject> prefabList = new List<GameObject>();
public GameObject Room1;
public GameObject Room2;
public GameObject Room3;
void Start()
{
prefabList.Add(Room1);
prefabList.Add(Room2);
prefabList.Add(Room3);
for (int i = 0; i < 5; i )
{
int prefabIndex = UnityEngine.Random.Range(0, prefabList.Count - 0);
var position = new Vector3(Random.Range(-20.0f, 20.0f), Random.Range(-10.0f, 10.0f));
Instantiate(prefabList[prefabIndex], position, Quaternion.identity);
}
}
}
我想重試將預制件放在不同的位置,但不知道該怎么做?
任何幫助都將不勝感激。
uj5u.com熱心網友回復:
有幾種方法可以解決這個問題,但這是一個有趣的問題。
使用這行代碼:
var position = new Vector3(Random.Range(-20.0f, 20.0f), Random.Range(-10.0f, 10.0f));
您在整個房間中隨機分布物件,但您可能會用完房間中的可用空間并產生更多的物件。
游戲解決“重疊物件”問題的方法有很多,但我更喜歡在這種情況下使用網格系統,而不是嘗試在關卡生成中涉及物理。
網格系統
您應該確定要生成的最大預制物件,然后將地圖分解為具有該大小或更大單元格的網格。然后,您可以創建一個元組串列,每個元組代表該網格上的一個單元格。從串列中隨機選擇 1 個元組,并在生成物件時將其洗掉,以保證該區域不會出現其他物件。
[SerializeField]
List<GameObject> prefabList = new List<GameObject>();
[SerializeField]
int numberToSpawn = 5;
[SerializeField]
Vector3 mapAnchor = Vector3.zero;
[SerializeField]
float mapWidth = 40f;
[SerializeField]
float mapHeight = 20f;
[SerializeField]
float cellSize = 1f;
// Start is called before the first frame update
void Start()
{
//calculate the number of cells along the width and height of the map
int cellWidth = Mathf.RoundToInt(mapWidth / cellSize);
int cellHeight = Mathf.RoundToInt(mapHeight / cellSize);
//Generate a list of tuples that represent each individual cell on the map
List<(int,int)> cells = gridInstantiate(cellWidth, cellHeight);
for (int i = 0; i<5; i )
{
//Randomly select the cell on the grid
int randCellIndex = Random.Range(0, cells.Count);
(int x, int y) = cells[randCellIndex];
cells.RemoveAt(randCellIndex);
//Instantiate the object at x and y on the grid, converting it back into world space
Vector3 position = mapAnchor;
position.x = position.x x * cellSize;
position.y = position.y y * cellSize;
Instantiate(prefabList[Random.Range(0, prefabList.Count)], position, Quaternion.identity);
}
}
List<(int,int)> gridInstantiate(int cellWidth, int cellHeight)
{
List<(int,int)> cells = new List<(int, int)>();
for (int i = 0; i < mapWidth; i )
{
for (int j = 0; j < mapHeight; j )
{
cells.Add((i, j));
}
}
return cells;
}
這就是使用上面的代碼生成隨機圓圈的樣子:

為了使物件更自然地生成,您可以添加一些額外的代碼來平滑它,方法是為每個單元格提供一個緩沖區,并允許實體化在該緩沖區內隨機化作為偏移量,從而防止它們如此完美地對齊:
添加另一個屬性:
[SerializeField]
float cellBuffer = 1f;
修改cellheight/cellwidth計算:
int cellWidth = Mathf.RoundToInt(mapWidth / (cellSize cellBuffer));
int cellHeight = Mathf.RoundToInt(mapHeight / (cellSize cellBuffer));
在緩沖區范圍內給位置一個隨機偏移量:
Vector3 offset = new Vector3(Random.Range(-cellBuffer / 2, cellBuffer / 2), Random.Range(-cellBuffer / 2, cellBuffer / 2), 0);
Instantiate(prefabList[Random.Range(0, prefabList.Count)], position offset, Quaternion.identity);
這是上面代碼更改添加的內容,另一個等距菱形精靈設定為另一個潛在的預制件,numberToSpawn 設定為 30:

為什么要這樣做,而不是隨機生成并檢查重疊?
如果您隨機生成并檢查重疊并且新物件的空間為零,則可能會遇到競爭條件。您要么不生成物件,要么繼續嘗試生成物件并失敗。使用此策略,單元格串列將包含地圖上所有剩余的“打開”位置以生成物件,因此您無需執行任何重疊檢查。此外,當該串列為空時,您可以知道沒有更多空間來生成物件。
uj5u.com熱心網友回復:
首先你需要知道你的房間有多大。一旦你在變數中擁有該資料,我們就將其稱為offSet。制作第一個房間后,您需要一個 if 陳述句來查看下一個預制件的位置是否有房間。如果有,則將第二個預制件偏移房間長度或寬度的距離。
Instantiate(prefabList[prefabIndex], offSet, Quaternion.identity);
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/483834.html
上一篇:統一的黑洞物理(2D)
