在Unity3D游戏开发中,经常需要生成和处理多个房间的场景,特别是在地牢生成、房屋布局或迷宫设计等应用中。为了确保生成的房间不会重叠,我们需要一种有效的去重叠化算法。以下将详细介绍该算法的原理和代码实现。
对惹,这里有一个游戏开发交流小组,大家可以点击进来一起交流一下开发经验呀!
算法原理
-
房间表示:
每个房间可以表示为一个矩形,其位置和大小由其在世界坐标系中的位置(x, y, z)以及宽度和高度决定。在Unity3D中,通常使用Rect组件或自定义的DungeonCell类来表示房间。 -
重叠检测:
重叠检测是判断两个房间是否相交的过程。这可以通过比较两个矩形的边界来实现。如果两个矩形的任意一边相交,则它们重叠。 -
移动房间:
一旦检测到重叠,就需要移动其中一个房间以避免重叠。移动的方向和距离可以根据重叠的严重程度来计算。一种简单的方法是计算两个房间中心点的差值,然后移动重叠的房间,使其中心点沿这个差值方向移动一定距离。 -
迭代处理:
由于移动一个房间可能会导致它与另一个房间重叠,因此需要迭代处理,直到所有房间都不重叠为止。
代码实现
以下是一个Unity3D中实现房间去重叠化算法的示例代码。
csharp复制代码
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using System.Linq; | |
public class DungeonCell : MonoBehaviour | |
{ | |
public Rect CellRect { get; private set; } | |
public Vector3 Position { get; private set; } | |
public int Width { get; private set; } | |
public int Height { get; private set; } | |
public CellType cellType { get; set; } | |
public enum CellType | |
{ | |
Normal, | |
Hall | |
} | |
public void CreateCell(int width, int height) | |
{ | |
Width = width; | |
Height = height; | |
Position = transform.position; | |
CellRect = new Rect(Position.x - Width / 2, Position.z - Height / 2, Width, Height); | |
} | |
public void MoveTo(Vector3 position) | |
{ | |
transform.position = position; | |
Position = position; | |
CellRect = new Rect(Position.x - Width / 2, Position.z - Height / 2, Width, Height); | |
} | |
public bool Overlap(DungeonCell comparedCell) | |
{ | |
return CellRect.Overlaps(comparedCell.CellRect); | |
} | |
} | |
public class DungeonMaker : MonoBehaviour | |
{ | |
public float CellCreationRadius = 150; | |
public int NumberOfCells = 40; | |
public int NumberOfHalls = 12; | |
public List<DungeonCell> cellsList = new List<DungeonCell>(); | |
public int MinWidth = 3; | |
public int MaxWidth = 8; | |
public int MinLength = 3; | |
public int MaxLength = 8; | |
public float movementForce = 4.0f; | |
public List<DungeonCell> importantCells = new List<DungeonCell>(); | |
void Start() | |
{ | |
CreateCells(); | |
SeparateCells(); | |
MarkImportantCell(); | |
} | |
private void CreateCells() | |
{ | |
for (int i = 0; i < NumberOfCells; i++) | |
{ | |
Vector2 Position2D = Random.insideUnitCircle * CellCreationRadius; | |
GameObject gameObjectPointer = new GameObject("Cell" + i); | |
DungeonCell cellPointer = gameObjectPointer.AddComponent<DungeonCell>(); | |
cellPointer.CreateCell(Random.Range(MinWidth, MaxWidth + 1), Random.Range(MinLength, MaxLength + 1)); | |
cellPointer.MoveTo(new Vector3(Position2D.x, 0, Position2D.y)); | |
cellsList.Add(cellPointer); | |
} | |
} | |
private void SeparateCells() | |
{ | |
bool allCellsNotOverlap = false; | |
while (!allCellsNotOverlap) | |
{ | |
allCellsNotOverlap = true; | |
foreach (DungeonCell currentCell in cellsList) | |
{ | |
Vector3 movementVector = Vector3.zero; | |
int numberOfOverlaps = 0; | |
foreach (DungeonCell comparedCell in cellsList) | |
{ | |
if (currentCell == comparedCell) continue; | |
if (currentCell.Overlap(comparedCell)) | |
{ | |
movementVector += currentCell.transform.position - comparedCell.transform.position; | |
numberOfOverlaps++; | |
} | |
} | |
if (numberOfOverlaps != 0) | |
{ | |
allCellsNotOverlap = false; | |
if (movementVector.magnitude > 0) | |
{ | |
movementVector = movementVector.normalized * movementForce; | |
} | |
else | |
{ | |
movementVector = Random.insideUnitCircle.normalized * movementForce; | |
} | |
currentCell.MoveTo(currentCell.transform.position + movementVector); | |
} | |
} | |
} | |
} | |
private void MarkImportantCell() | |
{ | |
importantCells = cellsList.OrderByDescending(n => n.CellRect.width * n.CellRect.height).ToList(); | |
for (int i = 0; i < NumberOfHalls; i++) | |
{ | |
importantCells[i].cellType = DungeonCell.CellType.Hall; | |
} | |
} | |
} |
技术详解
- DungeonCell 类:
CreateCell方法用于初始化房间的大小和位置,并计算其Rect边界。MoveTo方法用于更新房间的位置,并重新计算其Rect边界。Overlap方法用于检测两个房间是否重叠。
- DungeonMaker 类:
CreateCells方法用于随机生成指定数量的房间,并将它们添加到cellsList中。SeparateCells方法用于迭代处理房间重叠问题。通过计算重叠房间的移动向量,并将房间移动到新位置来避免重叠。MarkImportantCell方法用于根据房间大小将房间标记为重要房间(如大厅),以便后续处理。
通过该算法和代码实现,可以有效地解决Unity3D中房间重叠的问题,并为后续的房间布局和场景生成提供基础。
251

被折叠的 条评论
为什么被折叠?



