如何阻止实例化的预制件重叠 - Unity 2D?
How to stop Instantiated prefabs from overlapping - Unity 2D?
正如标题所说,我想知道如何才能阻止预制件重叠?
这是我当前的代码
{
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);
}
}
}
我想重新尝试将预制件放置在不同的位置,但不知道该怎么做?
感谢任何帮助。
首先你需要弄清楚你的房间有多大。一旦你有了一个变量中的数据,我们就称之为 offSet。一旦创建了第一个房间,您需要一个 if 语句来查看下一个预制件的位置是否有房间。如果有,则将第二个预制件偏移房间长度或宽度的距离。
Instantiate(prefabList[prefabIndex], offSet, Quaternion.identity);
有几种方法可以解决这个问题,但这是一个有趣的问题。
用这行代码:
var position = new Vector3(Random.Range(-20.0f, 20.0f), Random.Range(-10.0f, 10.0f));
您在整个房间内随机分布对象,但您可能 运行 在房间中无法生存 space,生成的对象数量更多。
游戏有几种方法可以解决“重叠对象”的问题,但我更喜欢在这种情况下使用网格系统,而不是尝试在关卡生成中涉及物理学。
网格系统
您应该确定要生成的最大预制对象,然后将您的地图分解成具有该大小或更大单元格的网格。然后,您可以创建一个 元组列表 ,每个元组代表该网格上的一个单元格。从列表中随机select 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:
为什么要这样做,而不是随机生成并检查重叠?
如果您随机生成并检查重叠并且新对象的 space 为零,则有可能 运行 进入竞争条件。您要么不生成对象,要么继续尝试生成对象并失败。使用此策略,单元格列表将包含地图上所有剩余的“开放”位置以在其上生成对象,因此您无需执行任何重叠检查。此外,当该列表为空时,您可以知道没有更多空间来生成对象。
正如标题所说,我想知道如何才能阻止预制件重叠?
这是我当前的代码
{
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);
}
}
}
我想重新尝试将预制件放置在不同的位置,但不知道该怎么做?
感谢任何帮助。
首先你需要弄清楚你的房间有多大。一旦你有了一个变量中的数据,我们就称之为 offSet。一旦创建了第一个房间,您需要一个 if 语句来查看下一个预制件的位置是否有房间。如果有,则将第二个预制件偏移房间长度或宽度的距离。
Instantiate(prefabList[prefabIndex], offSet, Quaternion.identity);
有几种方法可以解决这个问题,但这是一个有趣的问题。
用这行代码:
var position = new Vector3(Random.Range(-20.0f, 20.0f), Random.Range(-10.0f, 10.0f));
您在整个房间内随机分布对象,但您可能 运行 在房间中无法生存 space,生成的对象数量更多。
游戏有几种方法可以解决“重叠对象”的问题,但我更喜欢在这种情况下使用网格系统,而不是尝试在关卡生成中涉及物理学。
网格系统
您应该确定要生成的最大预制对象,然后将您的地图分解成具有该大小或更大单元格的网格。然后,您可以创建一个 元组列表 ,每个元组代表该网格上的一个单元格。从列表中随机select 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:
为什么要这样做,而不是随机生成并检查重叠?
如果您随机生成并检查重叠并且新对象的 space 为零,则有可能 运行 进入竞争条件。您要么不生成对象,要么继续尝试生成对象并失败。使用此策略,单元格列表将包含地图上所有剩余的“开放”位置以在其上生成对象,因此您无需执行任何重叠检查。此外,当该列表为空时,您可以知道没有更多空间来生成对象。