holopy3/Assets/Scripts/Maze.cs
2020-12-10 15:25:12 +01:00

317 lines
8.7 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
/*
* Please remember the bigger the maze the longer it will take for the system to generate it.
*
* Thank you
* TheAssetProvider
*
*/
//Cell class remembers the doors and the wether it has been visited by the system or not
[System.Serializable]
public class Zelle {
public bool visited;//visited or not
public GameObject north;//Called as 1
public GameObject east;//Called as 2
public GameObject west;//Called as 3
public GameObject south;//Called as 4
public Zelle (){
north = null;
east = null;
west = null;
south = null;
}
}
public class Maze : MonoBehaviour {
//Selecting GenerateAtStartup will generate a maze when the scene starts
//Selecting GenerateInEditor will let you generate the maze in the editor
//Selecting UseInGameTrigger will let you generate a maze by calling the Generate() function
public enum uses {GenerateAtStartup , GenerateInEditor , UseInGameTrigger};
public uses use;
//holds the wall prefab
public GameObject wall;
//Floor Type
public enum FloorTypes {None , PlaneFloor , SaparateFloorForEachCell};
public FloorTypes floorType;
//holds the floor prefab
public GameObject planeFloor;
//cell based floor
public GameObject cellFloor;
//X size of the maze
public int xSize = 10;
//Y size of the maze
public int ySize = 10;
//wall length on z axis
public float wallLength = 1.0f;
//position to start the generation of the grid
private Vector3 initialPos;
//holds all the walls
private GameObject wallHolder;
//holds all cells
private Zelle[] cells;
//total number of cells in the maze
private int totalCells = 0;
//how many cells have been visited by the script/system
private int visitedCells = 0;
//what cell is being processed
private int currentCell = 0;
//random neighbour
private int currentNeighbour = 0;
//holds a temp instance of the wall
private GameObject tempWall = null;
//how many cells have been processed
private int cellProcess = 0;
//started building the maze
private bool startedBuilding = false;
// which wall to break
private int wallToBreak = 0;
//last cell visited
private List<int> lastCell;
//backing up in pathway
private int backingUp = 0;
//
private GameObject floorHolder;
// Use this for initialization
void Start () {
if (use == uses.GenerateAtStartup)
Generate ();
}
public void Generate (){
if (!wall){
Debug.LogWarning("Please assign wall variable");
return;
}
if (xSize < 1 || ySize < 1) {
Debug.LogWarning("X and Y values can't be smaller than 1");
return;
}
if (floorType == FloorTypes.PlaneFloor&& !planeFloor) {
Debug.LogWarning("Please assign PlaneFloor variable");
return;
}
if (floorType == FloorTypes.SaparateFloorForEachCell && !cellFloor) {
Debug.LogWarning("Please assign CellFloor variable");
return;
}
//Setting the default values
//currentCell = 0;
backingUp = 0;
visitedCells = 0;
lastCell = new List<int>();
lastCell.Clear ();
wallHolder = new GameObject ();
wallHolder.name = "Maze";
initialPos = new Vector3 ((-xSize / 2) + wallLength/2, wallLength/2, (-ySize / 2) + wallLength);
//this will create the grid of walls
CreateWalls ();
}
void CreateWalls () {
Vector3 myPos = initialPos;
totalCells = xSize * ySize;
cells = new Zelle[totalCells];
GameObject floorCell;
if (floorType == FloorTypes.SaparateFloorForEachCell && cellFloor) {
floorHolder = new GameObject ();
floorHolder.name = "FloorHolder";
}
//For X
//Generates walls on the X axis
for (int j = 0; j < ySize; j++){
for (int i = 0; i <= xSize; i++) {
myPos = new Vector3(initialPos.x+(i*wallLength)-wallLength/2,0.5f,initialPos.z+(j*wallLength)-wallLength/2);
tempWall = Instantiate(wall,myPos,Quaternion.identity) as GameObject;
tempWall.transform.parent = wallHolder.transform;
//Generates floor for each cell
if (j < ySize && i < xSize && floorType == FloorTypes.SaparateFloorForEachCell && cellFloor){
floorCell = Instantiate(cellFloor,new Vector3(myPos.x +0.5f,0.0f,myPos.z),Quaternion.identity) as GameObject;
floorCell.transform.parent = floorHolder.transform;
}
}
}
//For Y
//Generates walls on the Z axis
for (int l = 0; l <= ySize; l++){
for (int k = 0; k < xSize;k++) {
myPos = new Vector3(initialPos.x+(k*wallLength),0.5f,initialPos.z+(l*wallLength)-wallLength);
tempWall = Instantiate(wall,myPos,Quaternion.Euler(0.0f,90.0f,0.0f)) as GameObject;
tempWall.transform.parent = wallHolder.transform;
}
}
//Assignes all the walls for all the cells
CreateCells ();
}
void CreateCells (){
GameObject[] allWalls;
int children = wallHolder.transform.childCount;
int termCount = 0;
int childProcess = 0;
int eastWestProcess = 0;
allWalls = new GameObject[children];
//Get all the walls in an array
for (int j = 0; j < children; ++j) {
allWalls[j] = wallHolder.transform.GetChild (j).gameObject;
}
//Assigning all the walls
for (cellProcess = 0; cellProcess < cells.Length; cellProcess++) {
if (termCount == xSize){
eastWestProcess ++;
termCount = 0;
}
cells[cellProcess] = new Zelle();
cells[cellProcess].east = allWalls[eastWestProcess];
cells[cellProcess].south = allWalls[childProcess+(xSize+1)*ySize];
eastWestProcess++;
termCount++;
childProcess++;
cells[cellProcess].west = allWalls[eastWestProcess];
cells[cellProcess].north = allWalls[(childProcess+(xSize+1)*ySize)+xSize-1];
}
//Now lets create the maze
CreateMaze ();
}
void CreateMaze (){
while (visitedCells < totalCells) {
if (startedBuilding){
//gives a random neighbour
GiveMeNieghbour();
if (cells[currentNeighbour].visited == false && cells[currentCell].visited == true){
//breaks the wall in betweel currentCell and neighbourCell
BreakWall();
cells[currentNeighbour].visited = true;
visitedCells++;
lastCell.Add(currentCell);
currentCell = currentNeighbour;
if (lastCell.Count > 0)
backingUp = lastCell.Count-1;
}
}
if (!startedBuilding){
currentCell = Random.Range(0,cells.Length);
startedBuilding = true;
cells[currentCell].visited = true;
visitedCells++;
}
//Invoke("CreateMaze",0.0f);
}
//else
//Generate Plane floor
if (floorType == FloorTypes.PlaneFloor && planeFloor) {
GenerateFloor();
}
//Activate Path Finder
if (transform.GetComponent<MazePathFinder> ()) {
transform.GetComponent<MazePathFinder> ().ActivatePathFinder(xSize,ySize,cells);
}
Debug.Log("Finished");
}
void BreakWall(){
switch (wallToBreak){
case 1 : DestroyImmediate(cells[currentCell].north); break;
case 2 : DestroyImmediate(cells[currentCell].east); break;
case 3 : DestroyImmediate(cells[currentCell].west); break;
case 4 : DestroyImmediate(cells[currentCell].south); break;
}
}
void GiveMeNieghbour (){
int length = 0;
int[] neighbour = new int[4];
int[] connectingWall = new int[4];
int check =0;
check = ((currentCell+1) / xSize);
check -= 1;
check *= xSize;
check += xSize;
//west
if (currentCell + 1 < totalCells && (currentCell+1) != check && xSize > 1) {
//Debug.Log(currentCell + 1);
if (cells[currentCell+1].visited == false){
neighbour[length] = currentCell+1;
connectingWall[length] = 3;
length++;
}
}
//east
if (currentCell - 1 >= 0 && currentCell != check && xSize > 1) {
//Debug.Log(currentCell - 1);
if (cells[currentCell-1].visited == false){
neighbour[length] = currentCell-1;
connectingWall[length] = 2;
length++;
}
}
//north
if (currentCell + xSize < totalCells && ySize > 1) {
//Debug.Log(currentCell+xSize);
if (cells[currentCell+xSize].visited == false){
neighbour[length] = currentCell+xSize;
connectingWall[length] = 1;
length++;
}
}
//south
if (currentCell - xSize >= 0 && ySize > 1) {
//Debug.Log(currentCell-xSize);
if (cells[currentCell-xSize].visited == false){
neighbour[length] = currentCell-xSize;
connectingWall[length] = 4;
length++;
}
}
if (length != 0){
int theChosenOne = Random.Range (0, length);
currentNeighbour = neighbour[theChosenOne];
wallToBreak = connectingWall[theChosenOne];
}
else {
if (backingUp >= 0){
currentCell = lastCell[backingUp];
backingUp--;
}
}
}
void GenerateFloor() {
//Mid point of the maze
Vector3 midPos = new Vector3 (initialPos.x + (wallLength * xSize/2.0f)-wallLength/2.0f, 0.0f, initialPos.z + (wallLength * ySize/2.0f)-wallLength);
//Spawn the floor
GameObject myFloor = Instantiate (planeFloor, midPos, Quaternion.identity) as GameObject;
//Scale the floor
myFloor.transform.localScale = new Vector3 (xSize * wallLength,1.0f,ySize * wallLength);
}
}