// Returns the maze, making the zones that belong to the road. private bool SolveMaze(ref Zone zone) { if (zone.x == end.x && zone.y == end.y) { zone.isPath = true; return(true); } if (zone.isPath) { return(false); } zone.isPath = true; for (Direction dir = Direction.NORTH; dir <= Direction.WEST; dir += (int)dir) { if ((zone.walls & (int)dir) != 0) // If does not exist a wall. { if (SolveMaze(ref zones[zone.x + DirectionFuncs.GetX(dir), zone.y + DirectionFuncs.GetY(dir)])) { return(true); } } } zone.isPath = false; return(false); }
// Generate the maze using the Growing Tree algorithm. private void GenerateMaze() { int x = Random.Range(0, width); int y = Random.Range(0, height); List <Zone> cells = new List <Zone>(); cells.Add(zones[x, y]); Direction[] directions = { Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST }; while (cells.Count > 0) { int index = ChooseIndex(cells.Count); x = cells[index].x; y = cells[index].y; Utils.Shuffle <Direction>(directions); foreach (Direction direction in directions) { int newX = x + DirectionFuncs.GetX(direction); int newY = y + DirectionFuncs.GetY(direction); if (newX >= 0 && newX < width && newY >= 0 && newY < height && zones[newX, newY].walls == 0) { zones[x, y].walls |= (int)direction; zones[newX, newY].walls |= (int)DirectionFuncs.GetOpposite(direction); cells.Add(zones[newX, newY]); index = -1; break; } } if (index > -1) { cells.RemoveAt(index); } } }
// Return a list with the available directions to continue navigating through the maze. private List <Direction> GetAvailableDirections(Zone zone, Direction from) { List <Direction> dirs = new List <Direction>(); Direction lastDirection = Direction.NONE; for (Direction dir = Direction.NORTH; dir <= Direction.WEST; dir += (int)dir) { if (dir != from) { if ((zone.walls & (int)dir) != 0) // If does not exist a wall. { if (zones[zone.x + DirectionFuncs.GetX(dir), zone.y + DirectionFuncs.GetY(dir)].isPath) // Always take the last the zone that leads to the last zone. { lastDirection = dir; } else { dirs.Add(dir); } } } } // Shuffle to not always take the same direction. if (dirs.Count > 1) { Utils.Shuffle <Direction>(dirs); } if (lastDirection != Direction.NONE) { dirs.Add(lastDirection); } return(dirs); }
// Generate filling rooms. private void GenerateFilling() { List <Room> fillingRooms = new List <Room>(); // NOTE: If a room has walls == 15, it means that nothing can be added to the room. // In the first iteration exists a possibility of creating a filling room touching some of the path rooms. // Store the rooms in a list to continue iterating later. for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { if (rooms[i, j].isPath && rooms[i, j].walls < 15) // 15 means that is not completely surrounded. { for (Direction dir = Direction.NORTH; dir <= Direction.WEST; dir += (int)dir) { int x = i + DirectionFuncs.GetX(dir); int y = j + DirectionFuncs.GetY(dir); if (x >= 0 && x < width && y >= 0 && y < height) { if (rooms[x, y].isNull) { if (Random.value > 0.5f) { rooms[x, y].filling = 1; rooms[x, y].isNull = false; rooms[i, j].walls |= (int)dir; rooms[x, y].walls |= (int)DirectionFuncs.GetOpposite(dir); fillingRooms.Add(rooms[x, y]); } } } } } } } // IMPORTANT: This is similar to the Drunkard Walk algorithm (Random Walk). int iterations = Random.Range(0, 4); int filling = 2; while (iterations > 0) { List <Room> nextFillingRooms = new List <Room>(); for (int i = 0; i < fillingRooms.Count; i++) { if (fillingRooms[i].walls < 15) { for (Direction dir = Direction.NORTH; dir <= Direction.WEST; dir += (int)dir) { int x = fillingRooms[i].x + DirectionFuncs.GetX(dir); int y = fillingRooms[i].y + DirectionFuncs.GetY(dir); if (x >= 0 && x < width && y >= 0 && y < height) { if (rooms[x, y].isNull) { if (Random.value > 0.5f) { rooms[x, y].filling = filling; rooms[x, y].isNull = false; rooms[fillingRooms[i].x, fillingRooms[i].y].walls |= (int)dir; rooms[x, y].walls |= (int)DirectionFuncs.GetOpposite(dir); nextFillingRooms.Add(rooms[x, y]); } } } } } } fillingRooms = nextFillingRooms; filling++; iterations--; } }
// Marks the zones that have keys and/or doors. private void CreateDoorsAndKeys(ref Zone zone, Direction from, ref int region, ref int order) { List <Direction> dirs = GetAvailableDirections(zone, from); if (dirs.Count == 0) { // Put a key. zone.key = ++region; zone.region = region; zone.order = ++order; order = 0; } else { // Continue iterating. int lastRegion = region; foreach (Direction dir in dirs) { if (lastRegion != region && dirs.Count > 1) { // Put a door. lastRegion = region; switch (dir) { case Direction.NORTH: zone.northDoor = region; break; case Direction.EAST: zone.eastDoor = region; break; case Direction.SOUTH: zone.southDoor = region; break; case Direction.WEST: zone.westDoor = region; break; } } if (zone.region == 0) { zone.region = region + 1; zone.order = ++order; } CreateDoorsAndKeys(ref zones[zone.x + DirectionFuncs.GetX(dir), zone.y + DirectionFuncs.GetY(dir)], DirectionFuncs.GetOpposite(dir), ref region, ref order); } } }