private void ConnectFarTaskNodesRooms(Room upperRoom, Room lowerRoom) { // Choose random cell in the lower part of the upper room int random = Random.Range(0, upperRoom.getTilesDownRow().Count - 1); DungeonCell firstCell = upperRoom.getTilesDownRow()[random].getCorrespondingDungeonCell(); // Choose random cell in the upper part of the lower room random = Random.Range(0, lowerRoom.getTilesUpRow().Count - 1); DungeonCell lastCell = lowerRoom.getTilesUpRow()[random].getCorrespondingDungeonCell(); // Check if both cells are aligned if (firstCell.getCellColumnPositionInGrid() == lastCell.getCellColumnPositionInGrid()) { dungeon.getDungeonCorridors().Add(new Corridor(dungeon, firstCell, lastCell, Direction.Down, floorTileDimensions, floorMaterial, wallHeight, wallMaterial, false)); } else { // Get first middle point between both rooms int middle = (firstCell.getCellRowPositionInGrid() + lastCell.getCellRowPositionInGrid()) / 2; DungeonCell firstMiddleCell = dungeon.getDungeonGrid()[middle, firstCell.getCellColumnPositionInGrid()]; // Get second middle point DungeonCell secondMiddleCell = dungeon.getDungeonGrid()[middle, lastCell.getCellColumnPositionInGrid()]; // Calculate direction of middle corridor Direction middleDirection = Direction.Right; if (firstMiddleCell.getCellColumnPositionInGrid() > secondMiddleCell.getCellColumnPositionInGrid()) { middleDirection = Direction.Left; } // Create corridors dungeon.getDungeonCorridors().Add(new Corridor(dungeon, firstCell, firstMiddleCell, Direction.Down, floorTileDimensions, floorMaterial, wallHeight, wallMaterial, true)); dungeon.getDungeonCorridors().Add(new Corridor(dungeon, firstMiddleCell, secondMiddleCell, middleDirection, floorTileDimensions, floorMaterial, wallHeight, wallMaterial, true)); dungeon.getDungeonCorridors().Add(new Corridor(dungeon, secondMiddleCell, lastCell, Direction.Down, floorTileDimensions, floorMaterial, wallHeight, wallMaterial, false)); } }
private void CreateRoomAndConnectNodes(Dictionary <AlphabetNode, Room> nodesWithRoom, List <AlphabetNode> nodesToVisit, AlphabetNode currentNode, Direction dir) { // Choose random corridor length to separate the rooms by that distance int randomCorridorLength = 1; if (dir == Direction.Right || dir == Direction.Left) { randomCorridorLength = Random.Range(minCorridorLengthWhenHorizontal, maxCorridorLengthWhenHorizontal); } else { randomCorridorLength = Random.Range(minCorridorLengthWhenVertical, maxCorridorLengthWhenVertical); } // Choose random room width int randomRoomWidth = Random.Range(roomMinTilesWidth, roomMaxTilesWidth); // Choose random room height int randomRoomHeight = Random.Range(roomMinTilesHeight, roomMaxTilesHeight); // Calculate top left corner column and row based on the direction and the middle cell of corresponding external side to align the rooms as much as possible int topLeftCornerColumn = 0; int topLeftCornerRow = 0; switch (dir) { case Direction.Right: int rigthColumnTilesNumber = nodesWithRoom[nodesToVisit[0]].getTilesRightColumn().Count; DungeonCell rightColumnMiddleCell = nodesWithRoom[nodesToVisit[0]].getTilesRightColumn()[rigthColumnTilesNumber / 2].getCorrespondingDungeonCell(); topLeftCornerColumn = rightColumnMiddleCell.getCellColumnPositionInGrid() + randomCorridorLength + 1; topLeftCornerRow = rightColumnMiddleCell.getCellRowPositionInGrid() - (randomRoomHeight / 2); break; case Direction.Left: int leftColumnTilesNumber = nodesWithRoom[nodesToVisit[0]].getTilesLeftColumn().Count; DungeonCell leftColumnMiddleCell = nodesWithRoom[nodesToVisit[0]].getTilesLeftColumn()[leftColumnTilesNumber / 2].getCorrespondingDungeonCell(); topLeftCornerColumn = leftColumnMiddleCell.getCellColumnPositionInGrid() - randomCorridorLength - randomRoomWidth; topLeftCornerRow = leftColumnMiddleCell.getCellRowPositionInGrid() - (randomRoomHeight / 2); break; case Direction.Up: int upRowTilesNumber = nodesWithRoom[nodesToVisit[0]].getTilesUpRow().Count; DungeonCell upRowMiddleCell = nodesWithRoom[nodesToVisit[0]].getTilesUpRow()[upRowTilesNumber / 2].getCorrespondingDungeonCell(); topLeftCornerColumn = upRowMiddleCell.getCellColumnPositionInGrid() - (randomRoomWidth / 2); topLeftCornerRow = upRowMiddleCell.getCellRowPositionInGrid() - randomCorridorLength - randomRoomHeight; break; case Direction.Down: int downRowTilesNumber = nodesWithRoom[nodesToVisit[0]].getTilesDownRow().Count; DungeonCell downRowMiddleCell = nodesWithRoom[nodesToVisit[0]].getTilesDownRow()[downRowTilesNumber / 2].getCorrespondingDungeonCell(); topLeftCornerColumn = downRowMiddleCell.getCellColumnPositionInGrid() - (randomRoomWidth / 2); topLeftCornerRow = downRowMiddleCell.getCellRowPositionInGrid() + randomCorridorLength + 1; break; } // Create room dungeon.getDungeonRooms().Add(new Room(dungeon, topLeftCornerRow, topLeftCornerColumn, randomRoomHeight, randomRoomWidth, floorTileDimensions, floorMaterial, wallHeight, wallMaterial)); // Add node to lists nodesWithRoom.Add(currentNode.getConnection(dir), dungeon.getDungeonRooms()[dungeon.getDungeonRooms().Count - 1]); nodesToVisit.Add(currentNode.getConnection(dir)); // Connect rooms dungeon.getDungeonCorridors().Add(new Corridor(dungeon, nodesWithRoom[currentNode], nodesWithRoom[currentNode.getConnection(dir)], floorTileDimensions, floorMaterial, wallHeight, wallMaterial)); }
// Method that will try to build a corridor from of the outer tiles of the last room placed private void TryToBuildCorridorFromRoom(Vector3 tileDimensions, Material floorMaterial, float wallHeight, Material wallMaterial) { // Reset dirty corridors variables dirtyCorridors.Clear(); lastTileUsedAsCorridorConnection = null; directionOfWallToRebuild = Direction.Unknown; // Try to place a corridor from one of the four outter walls of a room while (lastRoomPlacedPossibleTiles.Count > 0) { // Choose random list int i = Random.Range(0, lastRoomPlacedPossibleTiles.Count - 1); // Choose random list Direction randomDirection = (Direction)Random.Range(0, System.Enum.GetValues(typeof(Direction)).Length); while (!lastRoomPlacedPossibleTiles.ContainsKey(randomDirection)) { randomDirection = (Direction)Random.Range(0, System.Enum.GetValues(typeof(Direction)).Length); } List <FloorTile> randomList = lastRoomPlacedPossibleTiles[randomDirection]; // Choose random tile until all tiles have been checked while (randomList.Count > 0 && !corridorPlaced) { // Randomly select tile int j = Random.Range(0, randomList.Count - 1); FloorTile randomTile = randomList[j]; currentCell = randomTile.getCorrespondingDungeonCell(); DungeonCell lastCell = randomTile.getCorrespondingDungeonCell(); // Check if corridor can be created from random tile int emptyCells = 0; int rowLengthMultiplier = 0; int columnLengthMultiplier = 0; switch (randomDirection) { case Direction.Up: emptyCells = CheckEmptyCellsUp(); rowLengthMultiplier = -1; break; case Direction.Down: emptyCells = CheckEmptyCellsDown(); rowLengthMultiplier = 1; break; case Direction.Left: emptyCells = CheckEmptyCellsLeft(); columnLengthMultiplier = -1; break; case Direction.Right: emptyCells = CheckEmptyCellsRight(); columnLengthMultiplier = 1; break; } if (emptyCells > minCorridorsLength) { // Choose random length int length = Random.Range(minCorridorsLength, emptyCells - 1); length = Mathf.Min(length, maxCorridorsLength); // Set last cell lastCell = dungeon.getDungeonGrid()[currentCell.getCellRowPositionInGrid() + (rowLengthMultiplier * length), currentCell.getCellColumnPositionInGrid() + (columnLengthMultiplier * length)]; // Build corridor between first and last cell dungeon.getDungeonCorridors().Add(new Corridor(dungeon, currentCell, lastCell, randomDirection, tileDimensions, floorMaterial, wallHeight, wallMaterial, true)); corridorPlaced = true; // Add the corridor to the dirty corridors list dirtyCorridors.Add(dungeon.getDungeonCorridors()[dungeon.getDungeonCorridors().Count - 1]); // Set the current cell (outer room cell) as the last cell used as connection lastTileUsedAsCorridorConnection = currentCell.getCellFloorTile(); // Set the direction of the tile wall that will need to be removed directionOfWallToRebuild = randomDirection; // Set direction to randomDirection direction = randomDirection; // Set current cell to the last cell of the corridor currentCell = lastCell; } // Remove tile from list randomList.Remove(randomTile); } // Exit loop if corridor was placed if (corridorPlaced) { break; } // Remove list lastRoomPlacedPossibleTiles.Remove(randomDirection); } // Reset try again boolean tryAgain = false; }
private void BuildCorridor(Dungeon dungeon, DungeonCell firstCell, DungeonCell lastCell, bool leaveLastCellWalls, Vector3 floorDimensions, Material floorMaterial, float wallHeight, Material wallMaterial) { // Initialize list corridorTiles = new List <FloorTile>(); // Initialize game object corridor = new GameObject(); corridor.name = "Corridor"; // Set necessary variables DungeonCell startCell = firstCell; DungeonCell currentCell = firstCell; DungeonCell nextCell = firstCell; DungeonCell endCell = lastCell; // Traverse columns until the end cell column is reached while (true) { // If grid cell is empty place floor tile normally if (currentCell.getCellFloorTile() == null && currentCell.getCellColumnPositionInGrid() != endCell.getCellColumnPositionInGrid()) { // Create tile FloorTile tile = new FloorTile(currentCell, floorMaterial, floorDimensions, TileType.CorridorTile); // When traversing right or left the tile is going to need upper and down walls tile.placeWall(wallMaterial, wallHeight, Direction.Up); tile.placeWall(wallMaterial, wallHeight, Direction.Down); // Add tile to the list of corridor tiles corridorTiles.Add(tile); currentCell.setCellFloorTile(tile); } // Traverse right if (currentCell.getCellColumnPositionInGrid() < endCell.getCellColumnPositionInGrid()) { // If the grid cell has a tile with walls remove the ones that are not needed if (currentCell.getCellFloorTile().getTileType() == TileType.RoomOuterTile || currentCell.getCellFloorTile().getTileType() == TileType.CorridorTile) { // When traversing right always remove the right wall of current tile if there is one currentCell.getCellFloorTile().removeWall(Direction.Right); } // Get next cell nextCell = dungeon.getDungeonGrid()[currentCell.getCellRowPositionInGrid(), currentCell.getCellColumnPositionInGrid() + 1]; // Remove left wall of next cell if there is one if (nextCell.getCellFloorTile() != null) { nextCell.getCellFloorTile().removeWall(Direction.Left); } } // Traverse left else if (currentCell.getCellColumnPositionInGrid() > endCell.getCellColumnPositionInGrid()) { // If the grid cell has a tile with walls remove the ones that are not needed if (currentCell.getCellFloorTile().getTileType() == TileType.RoomOuterTile || currentCell.getCellFloorTile().getTileType() == TileType.CorridorTile) { // When traversing left always remove the left wall of current tile if there is one currentCell.getCellFloorTile().removeWall(Direction.Left); } nextCell = dungeon.getDungeonGrid()[currentCell.getCellRowPositionInGrid(), currentCell.getCellColumnPositionInGrid() - 1]; // Remove right wall of next cell if there is one if (nextCell.getCellFloorTile() != null) { nextCell.getCellFloorTile().removeWall(Direction.Right); } } // Current cell column and end cell column are the same else { // If grid cell is empty place floor tile with walls forming a corner if (currentCell.getCellFloorTile() == null) { // Check in which row direction (up or down) the corridor will go next Direction cornerWall1; if (currentCell.getCellRowPositionInGrid() < endCell.getCellRowPositionInGrid()) { // If the corridor needs to go down the corner wall needs to be placed up the current tile cornerWall1 = Direction.Up; } else { // If the corridor needs to go up the corner wall needs to be placed down the current tile cornerWall1 = Direction.Down; } // Check if the start cell is at the right or left of the current cell Direction cornerWall2; if (startCell.getCellColumnPositionInGrid() < currentCell.getCellColumnPositionInGrid()) { // When coming from the left, the wall of the corner corridor cell needs to be placed on the right cornerWall2 = Direction.Right; } else { // When coming from the right, the wall of the corner corridor cell needs to be placed on the left cornerWall2 = Direction.Left; } // Create tile FloorTile tile = new FloorTile(currentCell, floorMaterial, floorDimensions, TileType.CorridorTile); // Place corner tile walls if (!leaveLastCellWalls) { tile.placeWall(wallMaterial, wallHeight, cornerWall1); tile.placeWall(wallMaterial, wallHeight, cornerWall2); } // Add tile to the list of corridor tiles corridorTiles.Add(tile); currentCell.setCellFloorTile(tile); } // Exit loop break; } // Set current cell to next cell currentCell = nextCell; } // Traverse rows until the end cell row is reached while (true) { // If grid cell is empty place floor tile normally if (currentCell.getCellFloorTile() == null) { // Create tile FloorTile tile = new FloorTile(currentCell, floorMaterial, floorDimensions, TileType.CorridorTile); // When traversing up or down the tile is going to need right and left walls tile.placeWall(wallMaterial, wallHeight, Direction.Right); tile.placeWall(wallMaterial, wallHeight, Direction.Left); // Add tile to the list of corridor tiles corridorTiles.Add(tile); currentCell.setCellFloorTile(tile); } // Traverse down if (currentCell.getCellRowPositionInGrid() < endCell.getCellRowPositionInGrid()) { // If the grid cell has a tile with walls remove the ones that are not needed if (currentCell.getCellFloorTile().getTileType() == TileType.RoomOuterTile || currentCell.getCellFloorTile().getTileType() == TileType.CorridorTile) { // When traversing down always remove the down wall of current tile if there is one currentCell.getCellFloorTile().removeWall(Direction.Down); } // Get next cell nextCell = dungeon.getDungeonGrid()[currentCell.getCellRowPositionInGrid() + 1, currentCell.getCellColumnPositionInGrid()]; // Remove upper wall of next cell if there is one if (nextCell.getCellFloorTile() != null) { nextCell.getCellFloorTile().removeWall(Direction.Up); } } // Traverse up else if (currentCell.getCellRowPositionInGrid() > endCell.getCellRowPositionInGrid()) { // If the grid cell has a tile with walls remove the ones that are not needed if (currentCell.getCellFloorTile().getTileType() == TileType.RoomOuterTile || currentCell.getCellFloorTile().getTileType() == TileType.CorridorTile) { // When traversing up always remove the upper wall of current tile if there is one currentCell.getCellFloorTile().removeWall(Direction.Up); } nextCell = dungeon.getDungeonGrid()[currentCell.getCellRowPositionInGrid() - 1, currentCell.getCellColumnPositionInGrid()]; // Remove down wall of next cell if there is one if (nextCell.getCellFloorTile() != null) { nextCell.getCellFloorTile().removeWall(Direction.Down); } } // Current cell column and end cell column are the same, as the up or down traversal is done after the right or left, at this point the start and end cells are connected and no corners are needed else { // Exit loop break; } // Set current cell to next cell currentCell = nextCell; } // Set corridor game object in the tile at the middle of the tiles list corridor.transform.position = corridorTiles[corridorTiles.Count / 2].getCorrespondingDungeonCell().getCellWorldPosition(); // Set the tiles as children of the corridor game object foreach (FloorTile tile in corridorTiles) { tile.setParent(corridor, true); } }
// Method that will try to build a room from the cell the digger is currently at private void TryToPlaceRoom(int roomMinWidth, int roomMaxWidth, int roomMinHeight, int roomMaxHeight, Vector3 tileDimensions, Material floorMaterial, float wallHeight, Material wallMaterial) { // If a corridor was placed in the previous iteration, the room needs to start from the next cell to the actual current cell based on the direcion the digger agent was going DungeonCell previousCurrent = dungeon.getDungeonGrid()[currentCell.getCellRowPositionInGrid(), currentCell.getCellColumnPositionInGrid()]; Direction directionToRemoveWall = Direction.Unknown; if (corridorPlaced) { UpdateCurrentCellToNextCell(ref directionToRemoveWall); } // Check the number of empty tiles from the currentCell in the four directions int emptyCellsRight = CheckEmptyCellsRight(); int emptyCellsLeft = CheckEmptyCellsLeft(); int emptyCellsUp = CheckEmptyCellsUp(); int emptyCellsDown = CheckEmptyCellsDown(); // Check if there is enough space to create a room from current cell if (emptyCellsRight + emptyCellsLeft > roomMinWidth && emptyCellsUp + emptyCellsDown > roomMinHeight) { // To make sure that one of the room tiles is placed in the current cell, the maximum distance to move the starting cell is the room minimum tiles height/width int maximumDistanceUp = Mathf.Min(emptyCellsUp, roomMinHeight); int maximumDistanceLeft = Mathf.Min(emptyCellsLeft, roomMinWidth); // Rooms are created from the top left corner, meaning that the starting cell can be moved from the current cell up or left if there is space int topLeftCornerMinRow = currentCell.getCellRowPositionInGrid() - maximumDistanceUp + 1; int topLeftCornerMinColumn = currentCell.getCellColumnPositionInGrid() - maximumDistanceLeft + 1; // The max column and row are going to depend on the available cells at the right and down of the current cell int maxRow = currentCell.getCellRowPositionInGrid() + emptyCellsDown - 1; int topLeftCornerMaxRow = maxRow - roomMinHeight + 1; topLeftCornerMaxRow = topLeftCornerMaxRow > currentCell.getCellRowPositionInGrid() ? currentCell.getCellRowPositionInGrid() : topLeftCornerMaxRow; int maxColumn = currentCell.getCellColumnPositionInGrid() + emptyCellsRight - 1; int topLeftCornerMaxColumn = maxColumn - roomMinWidth + 1; topLeftCornerMaxColumn = topLeftCornerMaxColumn > currentCell.getCellColumnPositionInGrid() ? currentCell.getCellColumnPositionInGrid() : topLeftCornerMaxColumn; // Choose random row and column for the top left corner of the room int topLeftCornerRandomRow = Random.Range(topLeftCornerMinRow, topLeftCornerMaxRow); int topLeftCornerRandomColumn = Random.Range(topLeftCornerMinColumn, topLeftCornerMaxColumn); // Get max width and height from the row and column selected to be the top left corner of the room int maxWidth = Mathf.Min(maxColumn - topLeftCornerRandomColumn + 1, roomMaxWidth); int maxHeight = Mathf.Min(maxRow - topLeftCornerRandomRow + 1, roomMaxHeight); // Get random width and height int randomRoomWidth = Random.Range(roomMinWidth, maxWidth); int randomRoomHeight = Random.Range(roomMinHeight, maxHeight); // Given the top left corner, width and height, make sure that the room can still be placed if (AllTilesAreEmpty(topLeftCornerRandomRow, randomRoomHeight, topLeftCornerRandomColumn, randomRoomWidth)) { // Create new room dungeon.getDungeonRooms().Add(new Room(dungeon, topLeftCornerRandomRow, topLeftCornerRandomColumn, randomRoomHeight, randomRoomWidth, tileDimensions, floorMaterial, wallHeight, wallMaterial)); roomPlaced = true; // Get all possible tiles from which a corridor can be placed of the room currently added lastRoomPlacedPossibleTiles.Clear(); lastRoomPlacedPossibleTiles.Add(Direction.Up, dungeon.getDungeonRooms()[dungeon.getDungeonRooms().Count - 1].getTilesUpRow()); lastRoomPlacedPossibleTiles.Add(Direction.Down, dungeon.getDungeonRooms()[dungeon.getDungeonRooms().Count - 1].getTilesDownRow()); lastRoomPlacedPossibleTiles.Add(Direction.Left, dungeon.getDungeonRooms()[dungeon.getDungeonRooms().Count - 1].getTilesLeftColumn()); lastRoomPlacedPossibleTiles.Add(Direction.Right, dungeon.getDungeonRooms()[dungeon.getDungeonRooms().Count - 1].getTilesRightColumn()); // Remove wall from the previous current cell to connect the room and the corridor, if a corridor was placed in the previous iteration if (corridorPlaced) { previousCurrent.getCellFloorTile().removeWall(direction); currentCell.getCellFloorTile().removeWall(directionToRemoveWall); } } } // If room could not be placed, then set the current to be the previous current to properly connect a corridor with another corridor if (!roomPlaced) { currentCell = previousCurrent; } }