Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- public class Cell
- {
- //get grid position of the cell
- public Vector3 gridPos;
- //get reference to the actual cell obejct
- public GameObject cellObject;
- //get reference to the script of the cell
- public CellScript cScript;
- }
- public class CellScript : MonoBehaviour
- {
- //get references to the cells of the wall
- public GameObject wallL;
- public GameObject wallR;
- public GameObject wallU;
- public GameObject wallD;
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- //[ExecuteInEditMode]
- public class MazeGenerator : MonoBehaviour
- {
- #region Variables
- [SerializeField] int _mazeRows;
- [SerializeField] int _mazeColumns;
- [SerializeField] GameObject _cellPrefab;
- [SerializeField] bool _disableCellMesh = true;
- //make a dictionary to hold all cells and their grid position
- Dictionary<Vector3, Cell> _allCells = new Dictionary<Vector3, Cell>();
- //make two lists for cells that are being checked and the unvisited cells
- private List<Cell> _unvisited = new List<Cell>();
- private List<Cell> _stack = new List<Cell>();
- //references to cells
- private Cell _currentCell;
- private Cell _checkCell;
- private float _cellSize;
- //array to hold possible neighboring position
- private Vector3[] _neighboringPositions = new Vector3[] {Vector3.left, Vector3.right, new Vector3(0,0,1), new Vector3(0,0,-1)};
- //this array will hold 4 center cells, top, left, right, and bottom
- private Cell[] _centerCells = new Cell[4];
- private GameObject _mazeParent;
- AIController _aiController;
- #endregion
- private void Start()
- {
- _aiController = FindObjectOfType<AIController>();
- CreateLayout();
- }
- //create the grid
- private void CreateLayout()
- {
- InitializeLayout();
- var startPos = Vector3.zero;
- var spawnPos = startPos;
- //Loop through rows and columns to create a cell
- for (int x = 0; x < _mazeColumns; x++)
- {
- for (int z = 0; z < _mazeRows; z++)
- {
- //generate a cell here
- GenerateCell(spawnPos, new Vector3(x, 0, z));
- spawnPos.z += _cellSize;
- }
- //reset Z and increase X
- spawnPos.z = startPos.z;
- spawnPos.x += _cellSize;
- }
- //create the center cells and check which wall to be removed correctly
- CreateCenter();
- FunAlgorithim();
- //RemoveWallFromFirstCell();
- MakeExit();
- }
- private void InitializeLayout()
- {
- //it is better to keep the grid rows and columns ints are even and not odd
- if (IsOdd(_mazeRows)) _mazeRows--;
- if (IsOdd(_mazeColumns)) _mazeColumns--;
- //Limit size to 8x8 just to have a good looking maze
- if (_mazeRows <= 7) _mazeRows = 8;
- if (_mazeColumns <= 7) _mazeColumns = 8;
- _cellSize = _cellPrefab.transform.localScale.x;
- //Create a mazeParent
- _mazeParent = new GameObject();
- _mazeParent.transform.position = Vector3.zero;
- _mazeParent.name = "Maze";
- }
- private void FunAlgorithim()
- {
- //make the starting cell visited
- _unvisited.Remove(_currentCell);
- //while we have unvisited cells
- while (_unvisited.Count > 0)
- {
- //need to know about the neighbors around each cell, create a method to return a list of neighboring cells
- List<Cell> unvisitedNeighbors = GetNeighboringCells(_currentCell);
- if (unvisitedNeighbors.Count > 0)
- {
- //get a random cell from the neighbors list
- _checkCell = unvisitedNeighbors[Random.Range(0, unvisitedNeighbors.Count)];
- _stack.Add(_currentCell);
- //need to compare and remove wall as necessary
- CompareWalls(_currentCell, _checkCell);
- _currentCell = _checkCell;
- _unvisited.Remove(_currentCell);
- }
- else if (_stack.Count > 0)
- {
- //make current cell the most recently added cell from the stack
- _currentCell = _stack[_stack.Count - 1];
- _stack.Remove(_currentCell);
- }
- }
- }
- private List<Cell> GetNeighboringCells(Cell currentCell)
- {
- List<Cell> neighbors = new List<Cell>();
- //create a cell object
- Cell newCell = currentCell;
- var currentPos = currentCell.gridPos;
- //loop of all each possible neighbors(up, down,left right
- foreach(var pos in _neighboringPositions)
- {
- //get position of neighbor on grid relative to current
- Vector3 newPos = currentPos + pos;
- //if cell exists
- if(_allCells.ContainsKey(newPos)) newCell = _allCells[newPos];
- //if this cell is unvisited
- if(_unvisited.Contains(newCell)) neighbors.Add(newCell);
- }
- return neighbors;
- }
- //compare neighors with current to remove walls
- private void CompareWalls(Cell curCell, Cell nCell)
- {
- //iff neighbor cell is at the left of the new cell
- if(nCell.gridPos.x < curCell.gridPos.x)
- {
- RemoveWall(nCell.cScript,2);
- RemoveWall(curCell.cScript,1);
- }
- else if(nCell.gridPos.x > curCell.gridPos.x)
- {
- RemoveWall(nCell.cScript, 1);
- RemoveWall(curCell.cScript, 2);
- }
- else if(nCell.gridPos.z > curCell.gridPos.z)
- {
- RemoveWall(nCell.cScript, 4);
- RemoveWall(curCell.cScript, 3);
- }
- else if(nCell.gridPos.z < curCell.gridPos.z)
- {
- RemoveWall(nCell.cScript, 3);
- RemoveWall(curCell.cScript, 4);
- }
- }
- //generate the cell, takes position and the position as a key to be stored in the dictionary
- private void GenerateCell(Vector3 pos, Vector3 keyPos)
- {
- Cell newCell = new Cell();
- //reference the grip position
- newCell.gridPos = keyPos;
- //instantiate the cell
- newCell.cellObject = Instantiate(_cellPrefab, pos, _cellPrefab.transform.rotation);
- //child it to parent
- if(_mazeParent != null) newCell.cellObject.transform.parent = _mazeParent.transform;
- //for cleanliness, rename the cells based on the key position
- newCell.cellObject.name = $"Cell-X: {keyPos.x}, Z: {keyPos.z}";
- //reference the script
- newCell.cScript = newCell.cellObject.GetComponent<CellScript>();
- if(_disableCellMesh) newCell.cellObject.GetComponent<MeshRenderer>().enabled = false;
- //add it to lists
- _allCells[keyPos] = newCell;
- _unvisited.Add(newCell);
- }
- private void RemoveWall(CellScript cScript, int wallID)
- {
- //wallID helps to choose which wall you want
- switch (wallID)
- {
- case 1:
- cScript.wallL.SetActive(false);
- break;
- case 2:
- cScript.wallR.SetActive(false);
- break;
- case 3:
- cScript.wallU.SetActive(false);
- break;
- case 4:
- cScript.wallD.SetActive(false);
- break;
- }
- }
- private void CreateCenter()
- {
- //ger reference to 4 center cells
- _centerCells[0] = _allCells[new Vector3((_mazeColumns/2), 0, (_mazeRows /2) + 1)];
- RemoveWall(_centerCells[0].cScript, 4);
- RemoveWall(_centerCells[0].cScript, 2);
- _centerCells[1] = _allCells[new Vector3((_mazeColumns / 2 ) + 1, 0, (_mazeRows /2) +1)];
- RemoveWall(_centerCells[1].cScript, 4);
- RemoveWall(_centerCells[1].cScript, 1);
- _centerCells[2] = _allCells[new Vector3(_mazeColumns/2, 0, _mazeRows/2)];
- RemoveWall(_centerCells[2].cScript, 3);
- RemoveWall(_centerCells[2].cScript, 2);
- _centerCells[3] = _allCells[new Vector3((_mazeColumns /2) + 1, 0, (_mazeRows/2))];
- RemoveWall(_centerCells[3].cScript, 3);
- RemoveWall(_centerCells[3].cScript, 1);
- //need to ensure that the center cell has only one exit and entry
- //list of 4 ints, one is selected at random and the other 3 are removed from the unvisited list
- List<int> randomInts = new List<int> { 0, 1, 2, 3 };
- int startCell = randomInts[Random.Range(0, randomInts.Count)];
- randomInts.Remove(startCell);
- _currentCell = _centerCells[startCell];
- foreach(int i in randomInts)
- {
- _unvisited.Remove(_centerCells[i]);
- }
- }
- private void RemoveWallFromFirstCell()
- {
- foreach (var firstCell in _allCells)
- {
- if (firstCell.Key.x == 0 && firstCell.Key.z == 0)
- {
- var cell = firstCell.Value;
- RemoveWall(cell.cScript, 4);
- return;
- }
- }
- }
- private void MakeExit()
- {
- //find the edge cells
- List<Cell> edgeCells = new List<Cell>();
- foreach(var cell in _allCells)
- {
- if(cell.Key.x == 0 || cell.Key.x == _mazeColumns || cell.Key.z == 0 || cell.Key.z == _mazeRows)
- {
- edgeCells.Add(cell.Value);
- }
- }
- // Get edge cell randomly from list.
- Cell randomCell = edgeCells[Random.Range(0, edgeCells.Count)];
- //remove appropriate wall
- if (randomCell.gridPos.x == 0) RemoveWall(randomCell.cScript, 1);
- if (randomCell.gridPos.x == _mazeColumns) RemoveWall(randomCell.cScript, 2);
- else if (randomCell.gridPos.z == _mazeRows) RemoveWall(randomCell.cScript, 3);
- else RemoveWall(randomCell.cScript, 4);
- StartCoroutine(_aiController.SetDestination(randomCell.gridPos));
- }
- private bool IsOdd(int value)
- {
- return value % 2 != 0;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement