我试图创建一个地下城生成器。首先,我随意放置房间,然后在它们之间的空隙中生长迷宫。但是我遇到了一个问题,每次我运行我的迷宫算法时,它都会产生奇怪的无法到达的走廊:
看看那里的红色方块。玩家无法进入这些走廊。如何避免它们?这是一些代码:
public void createMaze(byte[][] dungeon) {
for (int y = 1; y < dungeon.length; y += 2) {
for (int x = 1; x < dungeon[0].length; x += 2) {
Vector2 pos = new Vector2(x, y);
if (dungeon[y][x] != 2 && dungeon[y][x] != 1){
growMaze(pos, dungeon);
}
}
}
}
public void growMaze(Vector2 pos, byte[][] dungeon) {
// Initialize some Lists and Vars
int lastDir = 0;
ArrayList<Vector2> cells = new ArrayList<Vector2>();
// Adding the startPosition to the cell list.
cells.add(pos);
// When the position is in the Grid
if(pos.y < dungeon.length - 2 && pos.y > 0 + 2 && pos.x < dungeon[0].length - 2 && pos.x > 0 + 2){
// And no walls or floors are around it
if(isPlaceAble(dungeon , pos)){
// Then place a corridor tile
dungeon[(int) pos.y][(int) pos.x] = 4;
}
}
// Here comes the algorithm.
while(!cells.isEmpty()){
// choose the latest cell
Vector2 choosedCell = cells.get(cells.size() - 1);
// Check again if the cell is in the grid.
if(choosedCell.y < dungeon.length - 2 && choosedCell.y > 0 + 2 && choosedCell.x < dungeon[0].length - 2 && choosedCell.x > 0 + 2){
// When that's true, then check in which directions the cell is able to move
boolean canGoNorth = dungeon[(int) (choosedCell.y + 1)][(int) choosedCell.x] == 0 && dungeon[(int) (choosedCell.y + 2)][(int) choosedCell.x] == 0;
boolean canGoSouth = dungeon[(int) (choosedCell.y - 1)][(int) choosedCell.x] == 0 && dungeon[(int) (choosedCell.y - 2)][(int) choosedCell.x] == 0;
boolean canGoEast = dungeon[(int) (choosedCell.y)][(int) choosedCell.x + 1] == 0 && dungeon[(int) (choosedCell.y)][(int) choosedCell.x + 2] == 0;
boolean canGoWest = dungeon[(int) (choosedCell.y)][(int) choosedCell.x - 1] == 0 && dungeon[(int) (choosedCell.y)][(int) choosedCell.x - 2] == 0;
// When there's no available direction, then remove the cell and break the loop...
if(!canGoNorth && !canGoSouth && !canGoEast && !canGoWest ){
cells.remove(cells.size() - 1);
break;
}
else{
// But if there's a available direction, then remove the cell from the list.
Vector2 savedCell = cells.get(cells.size() - 1);
cells.remove(cells.get(cells.size() - 1));
boolean placed = false;
// And place a new one into a new direction. This will happen as long as one is placed.
while(!placed){
// pick a random direction
int randomDirection = MathUtils.random(0,3);
int rdm = randomDirection;
// Init the length of the cells.
int length = 2;
// And now begin, if the direction and the random number fits, then dig the corridor. If no direction/number fits, then redo this until it works.
if(canGoNorth && rdm == 0 ){
int ycoord = 0;
for(int y = (int) choosedCell.y; y < choosedCell.y + length; y++){
dungeon[(int) y][(int) choosedCell.x] = 4;
}
Vector2 newCell = new Vector2(choosedCell.x, choosedCell.y + length);
cells.add(newCell);
lastDir = 0;
placed = true;
}
if(canGoSouth && rdm == 1 ){
int ycoord = 0;
for(int y = (int) choosedCell.y; y > choosedCell.y - length; y--){
dungeon[(int) y][(int) choosedCell.x] = 4;
}
Vector2 newCell = new Vector2(choosedCell.x, choosedCell.y - length);
cells.add(newCell);
lastDir = 1;
placed = true;
}
if(canGoEast && rdm == 2 ){
int xcoord = 0;
for(int x = (int) choosedCell.x; x < choosedCell.x + length; x++){
dungeon[(int) choosedCell.y][x] = 4;
}
Vector2 newCell = new Vector2(choosedCell.x + length, choosedCell.y );
cells.add(newCell);
lastDir = 2;
placed = true;
}
if(canGoWest && rdm == 3 ){
int xcoord = 0;
for(int x = (int) choosedCell.x; x > choosedCell.x - length; x--){
dungeon[(int) choosedCell.y][x] = 4;
}
Vector2 newCell = new Vector2(choosedCell.x - length, choosedCell.y );
cells.add(newCell);
lastDir = 3;
placed = true;
}
}
}
}
else{
cells.remove(cells.size() - 1);
}
}
// And finally delete dead end cells :) (Those who only got 3 Wall/Floor neighbours or 4)
killDeadEnds(dungeon);
}
那么如何避免这些无法到达的迷宫?
答案 0 :(得分:1)
您可以使用union-find结构快速查找和删除未连接到房间的所有单元格。请参阅:https://en.wikipedia.org/wiki/Disjoint-set_data_structure
您最初为每个走廊或房间单元创建一个不相交的集合,然后将相邻房间或单元格的每对集合联合起来。最后,删除与房间不在同一集合中的所有道路单元格。
Union-find也是一个很好的迷宫生成算法的基础,它只是Kruskal用于在应用于网格的图形(https://en.wikipedia.org/wiki/Kruskal%27s_algorithm)中查找生成树的算法。请参阅:http://weblog.jamisbuck.org/2011/1/3/maze-generation-kruskal-s-algorithm
在应用死角移除之前,您可以首先使用此算法生成迷宫。但它会改变迷宫的性格,所以也许你不想这样做。