/// <summary> /// Gets the tile in the direction numberOfTilesAway from the currentTile. /// </summary> /// <param name="currentTile">The current tile we are at</param> /// <param name="direction">The direction we want to go in</param> /// <param name="numberOfTilesAway">How many spaces we want to move</param> /// <returns>The tile we ended at or NULL if no tile exists</returns> protected Tile GetTileToDirection(Tile currentTile, ETileDirection direction, int numberOfTilesAway = 1) { switch (direction) { case ETileDirection.NORTH: return(GetTile(currentTile.X, currentTile.Y + numberOfTilesAway)); case ETileDirection.SOUTH: return(GetTile(currentTile.X, currentTile.Y - numberOfTilesAway)); case ETileDirection.EAST: return(GetTile(currentTile.X + numberOfTilesAway, currentTile.Y)); case ETileDirection.WEST: return(GetTile(currentTile.X - numberOfTilesAway, currentTile.Y)); case ETileDirection.NORTH_EAST: return(GetTile(currentTile.X + numberOfTilesAway, currentTile.Y + numberOfTilesAway)); case ETileDirection.NORTH_WEST: return(GetTile(currentTile.X - numberOfTilesAway, currentTile.Y + numberOfTilesAway)); case ETileDirection.SOUTH_EAST: return(GetTile(currentTile.X + numberOfTilesAway, currentTile.Y - numberOfTilesAway)); case ETileDirection.SOUTH_WEST: return(GetTile(currentTile.X - numberOfTilesAway, currentTile.Y - numberOfTilesAway)); default: return(null); } }
public static ETileDirection GetOppositeDirection(ETileDirection direction) { switch (direction) { case ETileDirection.EAST: return(ETileDirection.WEST); case ETileDirection.WEST: return(ETileDirection.EAST); case ETileDirection.NORTH: return(ETileDirection.SOUTH); case ETileDirection.SOUTH: return(ETileDirection.NORTH); case ETileDirection.NORTH_EAST: return(ETileDirection.NORTH_WEST); case ETileDirection.NORTH_WEST: return(ETileDirection.NORTH_EAST); case ETileDirection.SOUTH_EAST: return(ETileDirection.SOUTH_WEST); case ETileDirection.SOUTH_WEST: return(ETileDirection.SOUTH_EAST); default: return(ETileDirection.NONE); } }
/// <summary> /// Deals with the actual visiting of tiles. It works by picking a random direction /// to carve in, and then we carve the cell we want to go to and the wall in between /// the two cells. When carving happens we add the carved cells to the region that /// our current cell belongs to. This function also deals with the KeepSameDirectionPercentage /// that determines how windy/jagged our maze is. /// </summary> /// <param name="currentTile">The current tile we are carving from</param> /// <param name="forceDirection">A forced direction to carve in. If not passed it will pick randomly</param> /// <returns>The tile we ended up carving into or NULL if no tile was picked</returns> private Tile CarveTile(Tile currentTile, ETileDirection forceDirection = ETileDirection.NONE) { ETileDirection chosenDirection; if (forceDirection == ETileDirection.NONE) { List <ETileDirection> directions = new List <ETileDirection>(); foreach (ETileDirection direction in Tile.cardinal) { if (CanCarve(currentTile, direction)) { directions.Add(direction); } } if (directions.Count() == 0) { return(null); } if (directions.Contains(lastDirection) && UnityEngine.Random.Range(0, 100) < KeepSameDirectionPercentage) { chosenDirection = lastDirection; } else { chosenDirection = directions.ElementAt(UnityEngine.Random.Range(0, directions.Count())); } } else { chosenDirection = forceDirection; } lastDirection = chosenDirection; Tile nextTile = GetTileToDirection(currentTile, chosenDirection, 2); Tile wall = GetTileToDirection(currentTile, chosenDirection, 1); nextTile.Type = ETileType.FLOOR; wall.Type = ETileType.FLOOR; currentTile.ParentRegion.AddTile(wall); return(nextTile); }
/// <summary> /// This function is the maze generation. We use a simple growing tree /// algorithm to build our maze. This works with a few steps: /// 1) Pick a starting cell and add it to our list /// 2) while we have cells to pick /// 3) pick a random cell /// 4) pick a random unvisted neighbor /// 5) add the neighbor to the list /// 6) if no neighbors exist remove the cell from the list /// /// We then repeat this until all our cells are either visited /// or surrounded by visted cells. /// </summary> private void GeneratePaths() { for (int y = 1; y < MapSize.y; y += 2) { for (int x = 1; x < MapSize.x; x += 2) { Tile start = GetTile(x, y); if (start.IsFloor() || IsBorderTile(start)) { continue; } Stack <Tile> unvisited = new Stack <Tile>(); unvisited.Push(start); Region currentRegion = new Region(); // take a cell out of the list // carve a random cell next to it // add that cell to the list while (unvisited.Count > 0) { Tile currentTile = unvisited.Peek(); currentTile.Type = ETileType.FLOOR; currentRegion.AddTile(currentTile); Tile nextTile = CarveTile(currentTile); if (nextTile == null) { unvisited.Pop(); lastDirection = ETileDirection.NONE; } else { unvisited.Push(nextTile); } } Regions.Add(currentRegion); } } }
/// <summary> /// Determines if the currentTile is a border tile to any other tile. /// Border tile is defined as a border to a region, the map, or another visited tile. /// </summary> /// <param name="currentTile">The tile we want to check</param> /// <param name="skipDirection">Allows us to not look in a certain direction. /// This is so that if we are carving we aren't checking the tile we just came from /// </param> /// <returns>Whether or not the tile is a border tile</returns> protected bool IsBorderTile(Tile currentTile, ETileDirection skipDirection = ETileDirection.NONE) { foreach (ETileDirection direction in Enum.GetValues(typeof(ETileDirection))) { if (direction != skipDirection && direction != ETileDirection.NONE) { Tile tile = GetTileToDirection(currentTile, direction); if (CheckIfTileIsOutOfMapOrInRegion(tile)) { return(true); } if (!Tile.diagonals.Contains(direction) && tile.IsFloor()) { return(true); } } } return(false); }
/// <summary> /// Determines whether or not we can go from the currentTile /// and carve into the tile 2 spaces in the wanted direction. /// We use 2 spaces here because we need to carve through a /// wall and then carve through the cell we want to go to. /// </summary> /// <param name="currentTile">The tile we are at now</param> /// <param name="direction">The direction we want to carve in</param> /// <returns>Whether or not we can carve to the next tile</returns> private bool CanCarve(Tile currentTile, ETileDirection direction) { Tile tile = GetTileToDirection(currentTile, direction, 2); return(tile != null && !tile.IsFloor() && !IsBorderTile(tile, Tile.GetOppositeDirection(direction))); }