Procedurally generated Maze Implementation


Added a Maze generation system, which will create a unique maze every time we play a new game.

I have used DFS (depth-first search) with recursive backtracking for generating the Maze. The Maze consists of grid cells where each cell takes a cell prefab to present it in the game environment.

Detailed explanation of my Maze Generation code:

Class Structure

Class Name

MazeGenerator

Fields

Serialized Fields

  • MazeCell mazeCellPrefab

    • Prefab for individual maze cells.

  • Transform mazeHolder

    • Parent transform to hold the maze cells in the hierarchy.

  • int mazeWidth

    • Width of the maze grid.

  • int mazeLength

    • Length of the maze grid.

Private Fields

  • MazeCell[,] mazeGrid

    • 2D array representing the maze grid structure.

Methods

1. void Start()

Initializes the maze grid and begins the maze generation process.

Key Steps

  1. Grid Initialization:

    • Instantiates MazeCell prefabs for every cell in the grid based on mazeWidth and mazeLength.

    • Places cells in the correct position and stores them in the mazeGrid array.

    MazeCell cell = Instantiate(mazeCellPrefab, new Vector3(x, 0, z), Quaternion.identity); cell.SetCoordinates(x, z); mazeGrid[x, z] = cell; 
  2. Maze Generation:

    • Starts the maze generation using a coroutine.

    • Initial cell: (0, 0).

    StartCoroutine(GenerateMaze(null, GetACell(0, 0))); 

2. MazeCell GetACell(int x, int z)

Retrieves the maze cell at the specified coordinates (x, z).

3. IEnumerator GenerateMaze(MazeCell previousCell, MazeCell currentCell)

Recursive coroutine that generates the maze using depth-first search.

Key Steps

  1. Marks the currentCell as visited.

    currentCell.Visit(); 
  2. Clears the wall between previousCell and currentCell.

    ClearWalls(previousCell, currentCell); 
  3. Waits for a short duration to visualize the generation.

    yield return new WaitForSeconds(0.1f); 
  4. Recursively generates the maze for unvisited neighboring cells.

    MazeCell nextCell = GetANewUnVisitedCell(currentCell); if (nextCell != null) {     yield return GenerateMaze(currentCell, nextCell); } else {     yield break; } 

4. MazeCell GetANewUnVisitedCell(MazeCell currentCell)

Finds and returns a random unvisited neighboring cell of currentCell.

Process

  • Uses GetUnvisitedNeighbourCells to get all unvisited neighbors.

  • Selects one randomly using Random.Range.

  • Returns null if there are no unvisited neighbors.

5. List<MazeCell> GetUnvisitedNeighbourCells(MazeCell currentCell)

Retrieves a list of unvisited neighbors for a given cell.

Process

  1. Extracts the cell’s coordinates.

  2. Checks each neighboring direction (left, right, forward, backward).

  3. Adds unvisited neighbors to a list.

  4. Ensures neighbors are within grid bounds using CheckBound.

6. bool CheckBound(int x, int z)

Verifies if the coordinates (x, z) are within the grid bounds.

Logic

if ((x >= 0 && x < mazeWidth) && (z >= 0 && z < mazeLength)) {     return true; } else {     return false; } 

7. void ClearWalls(MazeCell previousCell, MazeCell currentCell)

Removes walls between two neighboring cells to create a path.

Wall Clearing Logic

  • Determines the direction between previousCell and currentCell.

  • Clears the walls accordingly:

    • Left -> Right: Clears right wall of previousCell and left wall of currentCell.

    • Right -> Left: Clears left wall of previousCell and right wall of currentCell.

    • Back -> Front: Clears front wall of previousCell and back wall of currentCell.

    • Front -> Back: Clears back wall of previousCell and front wall of currentCell.

Dependencies

1. MazeCell Class

Represents individual cells of the maze. Must include:

  • float X, Z: Coordinates of the cell.

  • bool isVisited: Indicates whether the cell has been visited.

  • void Visit(): Marks the cell as visited.

  • void ClearWall(CellWalls wall): Clears a specified wall.

  • void SetCoordinates(int x, int z): Sets the cell’s coordinates.

2. CellWalls Enum

Defines the walls of a cell (e.g., left, right, front, back).

Notes

  • Dynamic Cell Size:

    • Currently assumes a cell size of 1 unit.

    • To handle different sizes, adjust positions during instantiation (e.g., multiply coordinates by the cell size).

  • Maze Visualization:

    • The coroutine includes a WaitForSeconds delay to visualize the generation process step-by-step.


Check out this for code implementation: Maze

Leave a comment

Log in with itch.io to leave a comment.