📅  最后修改于: 2023-12-03 15:28:51.266000             🧑  作者: Mango
在2D游戏中,我们经常需要生成随机位置的物体,而且需要保证它们不会重叠。这里提供一种随机位置统一的解决方案,确保在整个游戏世界中,生成的随机物体不会重叠。
我们将整个游戏场景划分为一个二维网格(grid),然后将每个网格标记为已占用或未占用。当需要生成一个随机物体时,我们只需要在一个未占用的网格位置上生成物体,然后将该网格标记为已占用。
为了实现这一方案,我们需要进行以下步骤:
这种方式可以确保生成的物体不会重叠,并且可以在整个游戏世界中生成。但是,在某些情况下,这种方式可能会导致某些网格被占用,但是无法生成物体。例如,在网格的边缘附近,可能会没有足够的网格来生成物体。为了解决这个问题,我们可以使用动态网格(Dynamic Grid)来解决。
动态网格是一种特殊的网格,它可以在需要时自动创建和删除。当某些网格被占用时,我们可以添加动态网格来保证能够生成物体。当动态网格不再需要时,我们可以删除它们以减少内存使用。
我们可以定义一个动态网格类,它包含以下成员:
public class DynamicGrid
{
public int width; // 网格的宽度
public int height; // 网格的高度
public Vector2Int min; // 网格的最小索引
public Vector2Int max; // 网格的最大索引
public bool[,] occupied; // 网格占用状态
// 构造函数
public DynamicGrid(int w, int h)
{
width = w;
height = h;
min = new Vector2Int(0, 0);
max = new Vector2Int(w - 1, h - 1);
occupied = new bool[w, h];
}
// 添加动态网格,使物体在该网格中心生成
public Vector2Int AddGrid(Vector2 pos, int w, int h)
{
// 计算动态网格的索引
int x = (int)(pos.x / w);
int y = (int)(pos.y / h);
// 如果网格已经被占用,则向四周扩展网格
while (occupied[x, y])
{
// 计算当前网格周围的网格
List<Vector2Int> neighbors = GetNeighbors(new Vector2Int(x, y));
// 找到一个未占用的网格,生成物体
foreach (Vector2Int neighbor in neighbors)
{
if (!occupied[neighbor.x, neighbor.y])
{
x = neighbor.x;
y = neighbor.y;
break;
}
}
// 如果周围都被占用了,则扩展网格
if (occupied[x, y])
{
Expand();
}
}
// 标记该网格已占用
occupied[x, y] = true;
// 返回网格的中心点
return new Vector2Int((x + 0.5f) * w, (y + 0.5f) * h);
}
// 删除动态网格
public void RemoveGrid(Vector2Int pos, int w, int h)
{
// 计算网格的索引
int x = pos.x / w;
int y = pos.y / h;
// 标记网格未占用
occupied[x, y] = false;
// 如果该网格周围的网格都未占用,则删除该网格
List<Vector2Int> neighbors = GetNeighbors(new Vector2Int(x, y));
bool canRemove = true;
foreach (Vector2Int neighbor in neighbors)
{
if (occupied[neighbor.x, neighbor.y])
{
canRemove = false;
break;
}
}
if (canRemove)
{
Remove(new Vector2Int(x, y));
}
}
// 扩展网格
private void Expand()
{
// 扩展网格边界
if (min.x > 0) min.x--;
if (min.y > 0) min.y--;
if (max.x < width - 1) max.x++;
if (max.y < height - 1) max.y++;
// 创建新的网格状态数组
bool[,] newOccupied = new bool[width, height];
// 复制原来的网格状态
for (int x = min.x; x <= max.x; x++)
{
for (int y = min.y; y <= max.y; y++)
{
newOccupied[x, y] = occupied[x, y];
}
}
// 将新的网格状态赋值给原来的网格状态
occupied = newOccupied;
}
// 删除动态网格
private void Remove(Vector2Int pos)
{
// 移动所有网格
for (int x = pos.x + 1; x <= max.x; x++)
{
for (int y = min.y; y <= max.y; y++)
{
occupied[x - 1, y] = occupied[x, y];
}
}
// 缩小网格边界
max.x--;
// 创建新的网格状态数组
bool[,] newOccupied = new bool[width, height];
// 复制原来的网格状态
for (int x = min.x; x <= max.x; x++)
{
for (int y = min.y; y <= max.y; y++)
{
newOccupied[x, y] = occupied[x, y];
}
}
// 将新的网格状态赋值给原来的网格状态
occupied = newOccupied;
}
// 获取相邻的网格
private List<Vector2Int> GetNeighbors(Vector2Int pos)
{
List<Vector2Int> neighbors = new List<Vector2Int>();
if (pos.x > min.x) neighbors.Add(new Vector2Int(pos.x - 1, pos.y));
if (pos.x < max.x) neighbors.Add(new Vector2Int(pos.x + 1, pos.y));
if (pos.y > min.y) neighbors.Add(new Vector2Int(pos.x, pos.y - 1));
if (pos.y < max.y) neighbors.Add(new Vector2Int(pos.x, pos.y + 1));
return neighbors;
}
}
public class RandomObject : MonoBehaviour
{
public float width = 1.0f;
public float height = 1.0f;
public int gridSize = 10;
private DynamicGrid grid;
private void Start()
{
// 创建动态网格
grid = new DynamicGrid(gridSize, gridSize);
}
private void Update()
{
// 随机生成物体的位置
Vector2 pos = GetRandomPosition();
// 添加动态网格并生成物体
Vector2Int gridPos = grid.AddGrid(pos, (int)(width * gridSize), (int)(height * gridSize));
Instantiate(gameObject, gridPos, Quaternion.identity);
}
private Vector2 GetRandomPosition()
{
float x = Random.Range(0.0f, 10.0f);
float y = Random.Range(0.0f, 10.0f);
return new Vector2(x, y);
}
private void OnDestroy()
{
// 删除动态网格
grid.RemoveGrid(transform.position, (int)(width * gridSize), (int)(height * gridSize));
}
}
以上介绍完成,可以在C#中实现随机位置统一2D功能。