I am trying to generate a maze with rooms and I am using this guide
This is what I am trying to achieve. Instead I am getting this:
This is what I have done so far (with unnecessary parts taken out)
using UnityEngine;
using Random = UnityEngine.Random;
using UnityEngine.Tilemaps;
using System.Collections.Generic;
using System.Linq;
public class MazeAndRoomGenerator : MonoBehaviour
{
TileType[,] levelWall;
int[,] regions;
int currentRegion = -1;
enum TileType { Floor, Wall }
// CONSTANTS
readonly static int[] north = { 0, 1 };
readonly static int[] south = { 0, -1 };
readonly static int[] east = { 1, 0 };
readonly static int[] west = { -1, 0 };
readonly static int[] northEast = { 1, 1 };
readonly static int[] northWest = { -1, 1 };
readonly static int[] southEast = { 1, -1 };
readonly static int[] southWest = { -1, -1 };
readonly static int[][] northCells = { north, northEast, northWest };
readonly static int[][] southCells = { south, southEast, southWest };
readonly static int[][] eastCells = { east, northEast, southEast };
readonly static int[][] westCells = { west, northWest, southWest };
public void GenerateMaze()
{
// Loop through all cells in the level and grow the maze in all parts that aren't assigned yet
for (int y = 0; y < mapSize; y += 2)
{
for (int x = 0; x < mapSize; x += 2)
{
if(levelWall[x,y] == TileType.Wall)
{
GrowMaze(x, y);
}
}
}
}
public void Carve(int x, int y)
{
levelWall[x,y] = TileType.Floor;
regions[x, y] = currentRegion;
}
public bool CanCarve(int[] pos, int[] dir)
{
// Returns false if the cell is already taken or out of map bounds
int x = pos[0] + dir[0] * 2;
int y = pos[1] + dir[1] * 2;
if (!InBounds(x, y)) { return false; }
int[][] checkCells = null;
if (dir == north) { checkCells = northCells; }
else if (dir == south) { checkCells = southCells; }
else if (dir == east) { checkCells = eastCells; }
else if (dir == west) { checkCells = westCells; }
else { Debug.LogError("Incorrect direction inputted"); }
foreach (int[] checkCell in checkCells)
{
int[] cell = { pos[0] + checkCell[0], pos[1] + checkCell[1] };
if (CanCarve(cell))
{
return false;
}
}
// All of the surrounding walls are available so return true
return true;
}
public bool CanCarve(int[] pos)
{
// Returns false if the cell is already taken or out of map bounds
int x = pos[0];
int y = pos[1];
// Checking if map is out of bounds
if (!InBounds(x, y))
{
return false;
}
// return True if the cell is a wall (1)
// false if the cell is a floor (0)
return (levelWall[x, y] == TileType.Wall);
}
public bool InBounds(int x, int y)
{
// Checking if map is out of bounds
if (!(0 < x) || !(x < mapSize) ||
!(0 < y) || !(y < mapSize))
{
return false;
}
else return true;
}
public void GrowMaze(int startX, int startY)
{
/*
* RULES:
* If any of the neighbour cells to start point (CanCarve == false) are floor then stop.
* Take a random available direction and start carving.
* For each cell that is carved first check if the cell in front of it (travelling in the same direction)
* and the cells to the left and right of the cell is carvable.
* If isn't then remove that direction from available directions and pick new direction from original cell.
* Repeat until no available directions left
*/
int[][] directions = { north, south, east, west };
int[][] neighbourCells = { north, south, east, west, northEast, northWest, southEast, southWest };
int[] start = { startX, startY };
List<int[]> cells = new List<int[]>();
int[] lastDirection = null;
// Check if starting point is valid
foreach (int[] direction in neighbourCells)
{
int[] checkCell = { start[0] + direction[0], start[1] + direction[1] };
if (!CanCarve(checkCell))
{
// Throw out start cell and don't start maze from there
return;
}
}
// Start a new region for the new maze region
StartRegion();
Carve(start[0], start[1]);
cells.Add(start);
// While there are available cells to travel to run script
while (cells.Count > 0 && cells.Count < 10000)
{
int[] cell = cells[cells.Count - 1];
List<int[]> unmadeCells = new List<int[]>();
foreach (int[] direction in directions)
{
int[] checkCell = { cell[0] + direction[0], cell[1] + direction[1] };
if (CanCarve(checkCell, direction))
{
unmadeCells.Add(direction);
}
}
// If there are available cells to travel to run script
if (unmadeCells.Count > 0)
{
// Prefer to continue in the last direction travelling if available
// Random chance for it to choose a different direction
int[] direction;
if (unmadeCells.Contains(lastDirection)
&& (Random.value > (windingChance/100)) )
{
direction = lastDirection;
}
else
{
direction = unmadeCells[Random.Range(0, unmadeCells.Count)];
}
int[] newCell;
newCell = new int[] { cell[0] + direction[0], cell[1] + direction[1] };
Carve(newCell[0], newCell[1]);
// Adds new cell onto stack and script will repeat with this cell until it has no possible directions to travel
cells.Add(newCell);
lastDirection = direction;
}
else
{
cells.RemoveAt(cells.Count - 1);
lastDirection = null;
}
}
}
}
I have an idea that it is something to do with that the cells
array keeps increasing and is therefore stuck in a loop which is why I have added a restriction to the amount of cells in the while loop for debugging.
My rules for the maze are:
- If any of the neighbour cells to start point (CanCarve == false) are floor then stop.
- Take a random available direction and start carving.
- For each cell that is carved first check if the cell in front of it (travelling in the same direction) and the cells to the left and right of the cell is carvable. If isn't then remove that direction from available directions and pick new direction from original cell.
- Repeat until no available directions left
I would really appreciate any help. I've been ripping my hair out over this :)