有几种方法可以解决"重叠对象”的问题吗?

有几种方法可以解决

有几种方法可以处理这个问题,但这是一个有趣的方法。

使用这行代码:

var position = new Vector3(Random.Range(-20.0f, 20.0f), Random.Range(-10.0f, 10.0f));

您在整个房间内随机分配对象,但在生成更多对象的房间中可能会用完可用空间。

游戏有几种方法来解决“重叠对象”问题,但我更喜欢在这种情况下使用网格系统,而不是尝试在关卡生成中使用物理。

网格系统

您应该确定要生成的最大预制件,然后将地图拆分为具有该大小或更大单元格的网格。 然后您可以创建一个元组列表游戏运营,每个元组代表该网格上的一个单元格。 从列表中随机选择 1 个元组并在对象生成时将其删除,确保该区域中没有其他对象出现。

    [SerializeField]
    List prefabList = new List();
    [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;
    }

这就是使用上面的代码生成随机圆圈的样子:

Example of what it looks like generating 5 circle sprites

为了使对象更自然地相乘,您可以添加一些额外的代码,通过为每个单元格提供缓冲区,并允许实例化随机化到该缓冲区内的偏移量,防止它们完美对齐以使其平滑:

添加附加属性:

    [SerializeField]
    float cellBuffer = 1f;

修改单元格高度/单元格宽度计算:

        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:

Example of buffered generation

为什么要这样做而不是随机生成和判断重叠?

如果随机生成并判断重叠,并且新对象的空间为零,则可能存在竞争条件。 您要么不生成对象3D素材,要么继续尝试生成对象并失败。 使用此策略unity 实例化预制物体,单元格列表将包含所有剩余的对象,以便生成对象,因此无需执行重叠检查。 此外,当该列表为空时unity 实例化预制物体,您可以知道没有更多空间来生成对象。