Advertisement
NovusX

maze_generator

Aug 21st, 2021
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.16 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. public class Cell
  6. {
  7.     //get grid position of the cell
  8.     public Vector3 gridPos;
  9.     //get reference to the actual cell obejct
  10.     public GameObject cellObject;
  11.     //get reference to the script of the cell
  12.     public CellScript cScript;
  13.    
  14. }
  15.  
  16.  
  17. public class CellScript : MonoBehaviour
  18. {
  19.     //get references to the cells of the wall
  20.     public GameObject wallL;
  21.     public GameObject wallR;
  22.     public GameObject wallU;
  23.     public GameObject wallD;
  24.    
  25. }
  26.  
  27.  
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using UnityEngine;
  31.  
  32. //[ExecuteInEditMode]
  33. public class MazeGenerator : MonoBehaviour
  34. {
  35.     #region Variables
  36.     [SerializeField] int _mazeRows;
  37.     [SerializeField] int _mazeColumns;
  38.     [SerializeField] GameObject _cellPrefab;
  39.     [SerializeField] bool _disableCellMesh = true;
  40.  
  41.  
  42.     //make a dictionary to hold all cells and their grid position
  43.     Dictionary<Vector3, Cell> _allCells = new Dictionary<Vector3, Cell>();
  44.     //make two lists for cells that are being checked and the unvisited cells
  45.     private List<Cell> _unvisited = new List<Cell>();
  46.     private List<Cell> _stack = new List<Cell>();
  47.  
  48.  
  49.     //references to cells
  50.     private Cell _currentCell;
  51.     private Cell _checkCell;
  52.     private float _cellSize;
  53.  
  54.     //array to hold possible neighboring position
  55.     private Vector3[] _neighboringPositions = new Vector3[] {Vector3.left, Vector3.right, new Vector3(0,0,1), new Vector3(0,0,-1)};
  56.     //this array will hold 4 center cells, top, left, right, and bottom
  57.     private Cell[] _centerCells = new Cell[4];
  58.     private GameObject _mazeParent;
  59.  
  60.  
  61.     AIController _aiController;
  62.     #endregion
  63.  
  64.     private void Start()
  65.     {
  66.         _aiController = FindObjectOfType<AIController>();
  67.         CreateLayout();
  68.     }
  69.    
  70.     //create the grid
  71.     private void CreateLayout()
  72.     {
  73.         InitializeLayout();
  74.  
  75.         var startPos = Vector3.zero;
  76.         var spawnPos = startPos;
  77.  
  78.         //Loop through rows and columns to create a cell
  79.         for (int x = 0; x < _mazeColumns; x++)
  80.         {
  81.             for (int z = 0; z < _mazeRows; z++)
  82.             {
  83.                 //generate a cell here
  84.                 GenerateCell(spawnPos, new Vector3(x, 0, z));
  85.  
  86.                 spawnPos.z += _cellSize;
  87.             }
  88.  
  89.             //reset Z and increase X
  90.             spawnPos.z = startPos.z;
  91.             spawnPos.x += _cellSize;
  92.         }
  93.  
  94.         //create the center cells and check which wall to be removed correctly
  95.         CreateCenter();
  96.         FunAlgorithim();
  97.         //RemoveWallFromFirstCell();
  98.         MakeExit();
  99.        
  100.     }
  101.  
  102.     private void InitializeLayout()
  103.     {
  104.         //it is better to keep the grid rows and columns ints are even and not odd
  105.         if (IsOdd(_mazeRows)) _mazeRows--;
  106.         if (IsOdd(_mazeColumns)) _mazeColumns--;
  107.  
  108.         //Limit size to 8x8 just to have a good looking maze
  109.         if (_mazeRows <= 7) _mazeRows = 8;
  110.         if (_mazeColumns <= 7) _mazeColumns = 8;
  111.  
  112.         _cellSize = _cellPrefab.transform.localScale.x;
  113.  
  114.         //Create a mazeParent
  115.         _mazeParent = new GameObject();
  116.         _mazeParent.transform.position = Vector3.zero;
  117.         _mazeParent.name = "Maze";
  118.     }
  119.  
  120.     private void FunAlgorithim()
  121.     {
  122.         //make the starting cell visited
  123.         _unvisited.Remove(_currentCell);
  124.  
  125.         //while we have unvisited cells
  126.         while (_unvisited.Count > 0)
  127.         {
  128.             //need to know about the neighbors around each cell, create a method to return a list of neighboring cells
  129.             List<Cell> unvisitedNeighbors = GetNeighboringCells(_currentCell);
  130.             if (unvisitedNeighbors.Count > 0)
  131.             {
  132.                 //get a random cell from the neighbors list
  133.                 _checkCell = unvisitedNeighbors[Random.Range(0, unvisitedNeighbors.Count)];
  134.  
  135.                 _stack.Add(_currentCell);
  136.  
  137.                 //need to compare and remove wall as necessary
  138.                 CompareWalls(_currentCell, _checkCell);
  139.  
  140.                 _currentCell = _checkCell;
  141.                 _unvisited.Remove(_currentCell);
  142.             }
  143.             else if (_stack.Count > 0)
  144.             {
  145.                 //make current cell the most recently added cell from the stack
  146.                 _currentCell = _stack[_stack.Count - 1];
  147.                 _stack.Remove(_currentCell);
  148.             }
  149.         }
  150.     }
  151.  
  152.     private List<Cell> GetNeighboringCells(Cell currentCell)
  153.     {
  154.         List<Cell> neighbors = new List<Cell>();
  155.         //create a cell object
  156.         Cell newCell = currentCell;
  157.         var currentPos = currentCell.gridPos;
  158.  
  159.         //loop of all each possible neighbors(up, down,left right
  160.         foreach(var pos in _neighboringPositions)
  161.         {
  162.             //get position of neighbor on grid relative to current
  163.             Vector3 newPos = currentPos + pos;
  164.             //if cell exists
  165.             if(_allCells.ContainsKey(newPos)) newCell = _allCells[newPos];
  166.             //if this cell is unvisited
  167.             if(_unvisited.Contains(newCell)) neighbors.Add(newCell);
  168.         }
  169.  
  170.         return neighbors;
  171.     }
  172.  
  173.     //compare neighors with current to remove walls
  174.     private void CompareWalls(Cell curCell, Cell nCell)
  175.     {
  176.         //iff neighbor cell is at the left of the new cell
  177.         if(nCell.gridPos.x < curCell.gridPos.x)
  178.         {
  179.             RemoveWall(nCell.cScript,2);
  180.             RemoveWall(curCell.cScript,1);
  181.         }
  182.         else if(nCell.gridPos.x > curCell.gridPos.x)
  183.         {
  184.             RemoveWall(nCell.cScript, 1);
  185.             RemoveWall(curCell.cScript, 2);
  186.         }
  187.         else if(nCell.gridPos.z > curCell.gridPos.z)
  188.         {
  189.             RemoveWall(nCell.cScript, 4);
  190.             RemoveWall(curCell.cScript, 3);
  191.         }
  192.         else if(nCell.gridPos.z < curCell.gridPos.z)
  193.         {
  194.             RemoveWall(nCell.cScript, 3);
  195.             RemoveWall(curCell.cScript, 4);
  196.         }
  197.        
  198.     }
  199.  
  200.     //generate the cell, takes position and the position as a key to be stored in the dictionary
  201.     private void GenerateCell(Vector3 pos, Vector3 keyPos)
  202.     {
  203.         Cell newCell = new Cell();
  204.  
  205.         //reference the grip position
  206.         newCell.gridPos = keyPos;
  207.         //instantiate the cell
  208.         newCell.cellObject = Instantiate(_cellPrefab, pos, _cellPrefab.transform.rotation);
  209.         //child it to parent
  210.         if(_mazeParent != null) newCell.cellObject.transform.parent = _mazeParent.transform;
  211.         //for cleanliness, rename the cells based on the key position
  212.         newCell.cellObject.name = $"Cell-X: {keyPos.x}, Z: {keyPos.z}";
  213.         //reference the script
  214.         newCell.cScript = newCell.cellObject.GetComponent<CellScript>();
  215.         if(_disableCellMesh) newCell.cellObject.GetComponent<MeshRenderer>().enabled = false;
  216.  
  217.         //add it to lists
  218.         _allCells[keyPos] = newCell;
  219.         _unvisited.Add(newCell);
  220.     }
  221.  
  222.     private void RemoveWall(CellScript cScript, int wallID)
  223.     {
  224.         //wallID helps to choose which wall you want
  225.         switch (wallID)
  226.         {
  227.                 case 1:
  228.                 cScript.wallL.SetActive(false);
  229.                 break;
  230.                 case 2:
  231.                 cScript.wallR.SetActive(false);
  232.                 break;
  233.                 case 3:
  234.                 cScript.wallU.SetActive(false);
  235.                 break;
  236.                 case 4:
  237.                 cScript.wallD.SetActive(false);
  238.                 break;
  239.         }
  240.  
  241.     }
  242.  
  243.     private void CreateCenter()
  244.     {
  245.         //ger reference to 4 center cells
  246.         _centerCells[0] = _allCells[new Vector3((_mazeColumns/2), 0, (_mazeRows /2) + 1)];
  247.         RemoveWall(_centerCells[0].cScript, 4);
  248.         RemoveWall(_centerCells[0].cScript, 2);
  249.         _centerCells[1] = _allCells[new Vector3((_mazeColumns / 2 ) + 1, 0, (_mazeRows /2) +1)];
  250.         RemoveWall(_centerCells[1].cScript, 4);
  251.         RemoveWall(_centerCells[1].cScript, 1);
  252.         _centerCells[2] = _allCells[new Vector3(_mazeColumns/2, 0, _mazeRows/2)];
  253.         RemoveWall(_centerCells[2].cScript, 3);
  254.         RemoveWall(_centerCells[2].cScript, 2);
  255.         _centerCells[3] = _allCells[new Vector3((_mazeColumns /2) + 1, 0, (_mazeRows/2))];
  256.         RemoveWall(_centerCells[3].cScript, 3);
  257.         RemoveWall(_centerCells[3].cScript, 1);
  258.  
  259.         //need to ensure that the center cell has only one exit and entry
  260.         //list of 4 ints, one is selected at random and the other 3 are removed from the unvisited list
  261.         List<int> randomInts = new List<int> {  0, 1, 2, 3 };
  262.         int startCell = randomInts[Random.Range(0, randomInts.Count)];
  263.         randomInts.Remove(startCell);
  264.         _currentCell = _centerCells[startCell];
  265.         foreach(int i in randomInts)
  266.         {
  267.             _unvisited.Remove(_centerCells[i]);
  268.         }
  269.  
  270.     }
  271.  
  272.     private void RemoveWallFromFirstCell()
  273.     {
  274.         foreach (var firstCell in _allCells)
  275.         {
  276.             if (firstCell.Key.x == 0 && firstCell.Key.z == 0)
  277.             {
  278.                 var cell = firstCell.Value;
  279.                 RemoveWall(cell.cScript, 4);
  280.                 return;
  281.             }
  282.         }
  283.     }
  284.  
  285.     private void MakeExit()
  286.     {
  287.         //find the edge cells
  288.         List<Cell> edgeCells = new List<Cell>();
  289.         foreach(var cell in _allCells)
  290.         {
  291.             if(cell.Key.x == 0 ||  cell.Key.x == _mazeColumns || cell.Key.z == 0 || cell.Key.z == _mazeRows)
  292.             {
  293.                 edgeCells.Add(cell.Value);
  294.             }
  295.         }
  296.  
  297.         // Get edge cell randomly from list.
  298.         Cell randomCell = edgeCells[Random.Range(0, edgeCells.Count)];
  299.        
  300.  
  301.         //remove appropriate wall
  302.         if (randomCell.gridPos.x == 0) RemoveWall(randomCell.cScript, 1);
  303.         if (randomCell.gridPos.x == _mazeColumns) RemoveWall(randomCell.cScript, 2);
  304.         else if (randomCell.gridPos.z == _mazeRows) RemoveWall(randomCell.cScript, 3);
  305.         else RemoveWall(randomCell.cScript, 4);
  306.  
  307.         StartCoroutine(_aiController.SetDestination(randomCell.gridPos));
  308.     }
  309.  
  310.     private bool IsOdd(int value)
  311.     {
  312.         return value % 2 != 0;
  313.     }
  314.  
  315. }
  316.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement