/// <summary> /// Returns if the paths of the given moving walls overlap. /// This can only be true if the walls are parallel and in the same col/row. /// </summary> public static bool Overlap(MovingWall mw1, MovingWall mw2) { if (mw1.horizontal != mw2.horizontal) { return(false); } if (mw1.horizontal) { if (mw1.row != mw2.row) { return(false); } return(mw1.col < mw2.col + mw2.distance + mw2.size - 1 && mw2.col < mw1.col + mw1.distance + mw1.size - 1); } else { if (mw1.col != mw2.col) { return(false); } return(mw1.row < mw2.row + mw2.distance + mw2.size - 1 && mw2.row < mw1.row + mw1.distance + mw1.size - 1); } }
public void GenerateMaze(int width, int length) { // resetting grid. Every tile has all walls ClearGameObjects(); ResizeTiles(width, length); Tile tile = new Tile(); tile.leftWall = true; tile.upWall = true; tile.rightWall = true; tile.downWall = true; tile.tempVisited = false; for (int c = 0; c < width; c++) { for (int r = 0; r < length; r++) { tiles[c][r] = tile; } } // pick home base HomeBase = new Vector2Int(Random.Range(0, Width), Random.Range(0, Length)); // generating maze with recursive backtracker algorithm - https://en.wikipedia.org/wiki/Maze_generation_algorithm Stack <Vector2Int> stack = new Stack <Vector2Int>(); Vector2Int current = new Vector2Int(Random.Range(0, width), Random.Range(0, length)); Tile temp = tiles [current.x] [current.y]; temp.tempVisited = true; tiles[current.x][current.y] = temp; int numVisited = 1; while (numVisited < NumTiles) { // choose random adjacent unvisited tile List <Vector2Int> unvisitedNeighbors = new List <Vector2Int> (); if (current.x > 0 && !tiles[current.x - 1][current.y].tempVisited) { unvisitedNeighbors.Add(new Vector2Int(current.x - 1, current.y)); } if (current.y > 0 && !tiles[current.x][current.y - 1].tempVisited) { unvisitedNeighbors.Add(new Vector2Int(current.x, current.y - 1)); } if (current.x < width - 1 && !tiles[current.x + 1][current.y].tempVisited) { unvisitedNeighbors.Add(new Vector2Int(current.x + 1, current.y)); } if (current.y < length - 1 && !tiles[current.x][current.y + 1].tempVisited) { unvisitedNeighbors.Add(new Vector2Int(current.x, current.y + 1)); } if (unvisitedNeighbors.Count > 0) { // visit neighbor Vector2Int next = unvisitedNeighbors[Random.Range(0, unvisitedNeighbors.Count)]; stack.Push(current); // remove wall between tiles Tile currentTile = tiles[current.x][current.y]; Tile nextTile = tiles[next.x][next.y]; if (next.x > current.x) { currentTile.rightWall = false; nextTile.leftWall = false; } else if (next.y > current.y) { currentTile.upWall = false; nextTile.downWall = false; } else if (next.x < current.x) { currentTile.leftWall = false; nextTile.rightWall = false; } else { currentTile.downWall = false; nextTile.upWall = false; } nextTile.tempVisited = true; numVisited++; tiles[current.x][current.y] = currentTile; tiles[next.x][next.y] = nextTile; current = next; } else { // backtrack if no unvisited neighboring tiles if (stack.Count > 0) { current = stack.Pop(); } } } // make moving walls and clear walls that would be in the way int loopCount = 0; for (int i = 0; i < numMovingWalls; i++) { // break if can't find enough space for moving walls loopCount++; if (loopCount > 9999) { break; } MovingWall movingWall = Instantiate(movingWallPrefab, transform).GetComponent <MovingWall>(); movingWall.horizontal = true; //Random.value < .5f; if (movingWall.horizontal) { movingWall.size = Mathf.Min(movingWallSize, width - movingWallDistanceMin); } else { movingWall.size = Mathf.Min(movingWallSize, length - movingWallDistanceMin); } if (movingWall.horizontal) { movingWall.distance = Random.Range(Mathf.Min(movingWallDistanceMin, width - movingWall.size + 1), Mathf.Min(movingWallDistanceMax, width - movingWall.size + 1) + 1); movingWall.col = Random.Range(0, width - movingWall.distance + 1 - movingWall.size + 1); movingWall.row = Random.Range(1, length); } else { movingWall.distance = Random.Range(Mathf.Min(movingWallDistanceMin, length - movingWall.size + 1), Mathf.Min(movingWallDistanceMax, length - movingWall.size + 1) + 1); movingWall.col = Random.Range(1, width); movingWall.row = Random.Range(0, length - movingWall.distance + 1 - movingWall.size + 1); } movingWall.speed = Random.Range(movingWallSpeedMin, movingWallSpeedMax); // check that wall doesn't overlap with other walls (can intersect though) bool overlaps = false; foreach (MovingWall other in movingWalls) { if (MovingWall.Overlap(other, movingWall)) { overlaps = true; break; } } if (overlaps) { Destroy(movingWall.gameObject); i--; continue; } movingWall.SetRandomIndex(); movingWall.RemoveWallsInPath(); movingWall.UpdateTransform(); movingWalls.Add(movingWall); } numMovingWalls = movingWalls.Count; // remove vertical strips of walls if (openStripsWidth + mazeStripsWidth > 0) { int offset = 0; // (aligns with border width) for (; offset < width; offset += openStripsWidth + mazeStripsWidth) { for (int c = offset; c < Mathf.Min(offset + openStripsWidth, width); c++) { for (int r = 0; r < length; r++) { if (r > 0) { SetDownWall(c, r, false); } if (c > offset) { SetLeftWall(c, r, false); } } } } } // remove walls at left vertical border for (int c = 0; c < Mathf.Min(openStripsWidth, width); c++) { for (int r = 0; r < length; r++) { if (r > 0) { SetDownWall(c, r, false); } if (c > 0) { SetLeftWall(c, r, false); } } } // remove walls at right vertical border for (int c = Mathf.Max(width - openStripsWidth, 0); c < width; c++) { for (int r = 0; r < length; r++) { if (r > 0) { SetDownWall(c, r, false); } if (c > 0) { SetLeftWall(c, r, false); } } } // remove walls at bottom horizontal border for (int r = 0; r < Mathf.Min(openStripsWidth, length); r++) { for (int c = 0; c < width; c++) { if (r > 0) { SetDownWall(c, r, false); } if (c > 0) { SetLeftWall(c, r, false); } } } // remove walls at top horizontal border for (int r = Mathf.Max(length - openStripsWidth, 0); r < length; r++) { for (int c = 0; c < width; c++) { if (r > 0) { SetDownWall(c, r, false); } if (c > 0) { SetLeftWall(c, r, false); } } } // instantiate gameObjects GameObject groundTile = Instantiate(tilePrefab, transform); groundTile.transform.localPosition = new Vector3(TILE_SPACING * (width - 1) / 2, groundTile.transform.localPosition.y - .01f, TILE_SPACING * (length - 1) / 2); groundTile.transform.localScale = new Vector3(TILE_SPACING * width, groundTile.transform.localScale.y, TILE_SPACING * length); tileGameObjects.Add(groundTile); for (int c = 0; c < width; c++) { for (int r = 0; r < length; r++) { tile = tiles[c][r]; // add tile, but only if it's home base if (c == HomeBase.x && r == HomeBase.y) { GameObject tileGO = Instantiate(tilePrefab, transform); tileGO.transform.localPosition = new Vector3(TILE_SPACING * c, tileGO.transform.localPosition.y, TILE_SPACING * r); tileGameObjects.Add(tileGO); tileGO.GetComponent <ZombieMaze.Tile>().IsHomeBase = true; } GameObject wallGO; if (tile.leftWall) { wallGO = Instantiate(wallPrefab, transform); wallGO.transform.localPosition = new Vector3( TILE_SPACING * (c - .5f), wallGO.transform.localPosition.y, TILE_SPACING * r ); wallGO.transform.localRotation = Quaternion.Euler(0, 90, 0); wallGameObjects.Add(wallGO); } if (tile.downWall) { wallGO = Instantiate(wallPrefab, transform); wallGO.transform.localPosition = new Vector3( TILE_SPACING * c, wallGO.transform.localPosition.y, TILE_SPACING * (r - .5f) ); wallGO.transform.localRotation = Quaternion.Euler(0, 0, 0); wallGameObjects.Add(wallGO); } if (c == width - 1 && tile.rightWall) { wallGO = Instantiate(wallPrefab, transform); wallGO.transform.localPosition = new Vector3( TILE_SPACING * (c + .5f), wallGO.transform.localPosition.y, TILE_SPACING * r ); wallGO.transform.localRotation = Quaternion.Euler(0, 90, 0); wallGameObjects.Add(wallGO); } if (r == length - 1 && tile.upWall) { wallGO = Instantiate(wallPrefab, transform); wallGO.transform.localPosition = new Vector3( TILE_SPACING * c, wallGO.transform.localPosition.y, TILE_SPACING * (r + .5f) ); wallGO.transform.localRotation = Quaternion.Euler(0, 0, 0); wallGameObjects.Add(wallGO); } } } CreateCapsules(numCapsules); CreateZombies(numZombies); Camera.main.GetComponent <CameraControl>().InitialSetUp(); }