public void DefaultCorridorGenerator(DungeonBSPNode dungeonNode) { DungeonBSPNode leftChild = dungeonNode.LeftChild; DungeonBSPNode rightChild = dungeonNode.RightChild; DiggerGnome digger = new DiggerGnome(TargetMap); if (leftChild == null || !leftChild.RoomBuilt) dungeonNode.BoundingRect = rightChild.BoundingRect; else if (rightChild == null || !rightChild.RoomBuilt) dungeonNode.BoundingRect = leftChild.BoundingRect; else { // Draw a corridor between our child nodes. We have been keeping track of their bounding rectangles // as we've worked our way up the tree, so we can use that ensure we connect corridors to rooms if (dungeonNode.SplitOrientation == DungeonBSPNode.Orientation.Horizontal) { // child nodes were split horizontally, so draw a horizontal corridor between them. // If the nodes' regions overlap vertically by at least 3 (leaving room for walls), then we can just dig a // single horizontal tunnel to connect them; otherwise, we need to dig an 'L' shapped corridor to connect them. int minOverlappingY = Math.Max(leftChild.BoundingRect.Top, rightChild.BoundingRect.Top); int maxOverlappingY = Math.Min(leftChild.BoundingRect.Bottom, rightChild.BoundingRect.Bottom); if (maxOverlappingY - minOverlappingY >= 3) { // The regions overlap; we can dig a single horizontal corridor to connect them // Determine the range of Y axis values that we can dig at in order to connect the regions int corridorY = minOverlappingY + 1 + Rand.Next(maxOverlappingY - minOverlappingY - 2); // Start at the border between the two regions at Y=corridorY and dig towards the outside // edge of each region; we are gauranteed to eventually hit something since the regions' bounding // rects overlapped. digger.Dig(leftChild.BoundingRect.Right, corridorY, Direction.Left, 0, true); digger.Dig(leftChild.BoundingRect.Right + 1, corridorY, Direction.Right, 0, true); } else { // They don't overlap enough; dig an 'L' shaped corridor to connect them. int tunnelMeetX, tunnelMeetY; // Note that some of the math below (in particular the Mins and Maxs) are because the regions *can* be slightly overlapping in // the appropriate dimension; we don't draw a straight line if they overlap by less than 3 (to minimize the number of odd corridors // that attach to the outside corner of a room) if (leftChild.BoundingRect.Top > rightChild.BoundingRect.Top) { // Left child region's bounding rect is below the Right child region's bound rect. // _____ // X____| | // | | R | // | |___| // __|__ // | | // | L | // |___| tunnelMeetX = RandomValueBetween(leftChild.BoundingRect.Left + 1, leftChild.BoundingRect.Right); tunnelMeetY = RandomValueBetween(rightChild.BoundingRect.Top + 1, Math.Min(rightChild.BoundingRect.Bottom - 1, leftChild.BoundingRect.Top)); digger.DigDownRightCorridor(tunnelMeetX, tunnelMeetY, tunnelMeetX, tunnelMeetY); } else { // Left child region's bounding rect is above the Right child region's bound rect. // _____ // | |____X // | L | | // |___| | // __|__ // | | // | R | // |___| tunnelMeetX = RandomValueBetween(rightChild.BoundingRect.Left + 1, rightChild.BoundingRect.Right); tunnelMeetY = RandomValueBetween(leftChild.BoundingRect.Top + 1, Math.Min(leftChild.BoundingRect.Bottom - 1, rightChild.BoundingRect.Top)); digger.DigDownLeftLCorridor(tunnelMeetX, tunnelMeetY, tunnelMeetX, tunnelMeetY); } } // TBD: Need to set bounding rect for Special Rooms } else // Vertical split { // child nodes were split vertically, so draw a vertical corridor between them. // If the nodes' regions overlap horizontally by at least 3 (leaving room for walls), then we can just dig a // single vertical tunnel to connect them; otherwise, we need to dig an 'L' shapped corridor to connect them. int minOverlappingX = Math.Max(leftChild.BoundingRect.Left, rightChild.BoundingRect.Left); int maxOverlappingX = Math.Min(leftChild.BoundingRect.Right, rightChild.BoundingRect.Right); if (maxOverlappingX - minOverlappingX >= 3) { // The regions overlap; we can dig a single vertical corridor to connect them // Determine the range of X axis values that we can dig at in order to connect the regions int corridorX = minOverlappingX + 1 + Rand.Next(maxOverlappingX - minOverlappingX - 2); // Start at the border between the two regions at X=corridorX and dig towards the outside // edge of each region; we are gauranteed to eventually hit something since the regions' bounding // rects overlapped. digger.Dig(corridorX, leftChild.BoundingRect.Bottom, Direction.Up, 0, true); digger.Dig(corridorX, leftChild.BoundingRect.Bottom + 1, Direction.Down, 0, true); } else { // They don't overlap enough; dig an 'L' shaped corridor to connect them. int tunnelMeetX, tunnelMeetY; if (leftChild.BoundingRect.Left > rightChild.BoundingRect.Left) { // _____ // | | // | L | // |___| // _____ | // | | | // | R |___|X // |___| tunnelMeetX = RandomValueBetween(Math.Max(leftChild.BoundingRect.Left + 1, rightChild.BoundingRect.Right + 1), leftChild.BoundingRect.Right); tunnelMeetY = RandomValueBetween(rightChild.BoundingRect.Top + 1, rightChild.BoundingRect.Bottom); digger.DigUpLeftCorridor(tunnelMeetX, tunnelMeetY, tunnelMeetX, tunnelMeetY); } else { // _____ // | | // | L | // |___| // | _____ // | | | // X|____| R | // |___| tunnelMeetX = RandomValueBetween(leftChild.BoundingRect.Left, Math.Min(rightChild.BoundingRect.Left, leftChild.BoundingRect.Right - 1)); tunnelMeetY = RandomValueBetween(rightChild.BoundingRect.Top + 1, rightChild.BoundingRect.Bottom); digger.DigUpRightLCorridor(tunnelMeetX, tunnelMeetY, tunnelMeetX, tunnelMeetY); } } } // Determine our bounding rectangle (as the union of our child nodes' rectangles). dungeonNode.BoundingRect = Rectangle.Union(leftChild.BoundingRect, rightChild.BoundingRect); } // TBD: Not quite right - "RoomOrCorridorBuilt" more accurate dungeonNode.RoomBuilt = true; }
private void BruteForceConnectRooms(DungeonBSPNode regionA, DungeonBSPNode regionB) { // We don't care if we go through existing rooms; the goal is that we actually get atypical rooms... DiggerGnome digger = new DiggerGnome(TargetMap); if (regionA.BoundingRect.Bottom < regionB.BoundingRect.Top || regionB.BoundingRect.Bottom < regionA.BoundingRect.Top) { // Vertical split. Determine which one is the upper & lower region DungeonBSPNode upperRegion = (regionA.BoundingRect.Bottom <= regionB.BoundingRect.Top) ? regionA : regionB; DungeonBSPNode lowerRegion = (upperRegion == regionA) ? regionB : regionA; // If the nodes' regions overlap horizontally by at least 3 (leaving room for walls), then we can just dig a // single vertical tunnel to connect them; otherwise, we need to dig an 'L' shapped corridor to connect them. int minOverlappingX = Math.Max(upperRegion.BoundingRect.Left, lowerRegion.BoundingRect.Left); int maxOverlappingX = Math.Min(upperRegion.BoundingRect.Right, lowerRegion.BoundingRect.Right); if (maxOverlappingX - minOverlappingX >= 3) { // The regions overlap; we can dig a single vertical corridor to connect them // Determine the range of X axis values that we can dig at in order to connect the regions int corridorX = minOverlappingX + 1 + Rand.Next(maxOverlappingX - minOverlappingX - 2); // Start at the border between the two regions at X=corridorX and dig towards the outside // edge of each region; we are gauranteed to eventually hit something since the regions' bounding // rects overlapped. digger.Dig(corridorX, upperRegion.BoundingRect.Bottom, Direction.Up, 0, true); digger.Dig(corridorX, upperRegion.BoundingRect.Bottom + 1, Direction.Down, lowerRegion.BoundingRect.Top - (upperRegion.BoundingRect.Bottom + 1), true); } else { // They don't overlap enough; dig an 'L' shaped corridor to connect them. int tunnelMeetX, tunnelMeetY; if (upperRegion.BoundingRect.Left > lowerRegion.BoundingRect.Left) { // _____ // | | // | L | // |___| // _____ | // | | | // | R |___|X // |___| tunnelMeetX = RandomValueBetween(Math.Max(upperRegion.BoundingRect.Left + 1, lowerRegion.BoundingRect.Right + 1), upperRegion.BoundingRect.Right); tunnelMeetY = RandomValueBetween(lowerRegion.BoundingRect.Top + 1, lowerRegion.BoundingRect.Bottom); digger.DigUpLeftCorridor(tunnelMeetX, tunnelMeetY, lowerRegion.BoundingRect.Right, upperRegion.BoundingRect.Bottom); } else { // _____ // | | // | L | // |___| // | _____ // | | | // X|____| R | // |___| tunnelMeetX = RandomValueBetween(upperRegion.BoundingRect.Left + 1, Math.Min(lowerRegion.BoundingRect.Left, upperRegion.BoundingRect.Right - 1)); tunnelMeetY = RandomValueBetween(lowerRegion.BoundingRect.Top + 1, lowerRegion.BoundingRect.Bottom); digger.DigUpRightLCorridor(tunnelMeetX, tunnelMeetY, lowerRegion.BoundingRect.Left, upperRegion.BoundingRect.Bottom); } } } else { // Horizontal split. Determine which one is the left & right region DungeonBSPNode leftRegion = (regionA.BoundingRect.Right <= regionB.BoundingRect.Left) ? regionA : regionB; DungeonBSPNode rightRegion = (leftRegion == regionA) ? regionB : regionA; // If the nodes' regions overlap vertically by at least 3 (leaving room for walls), then we can just dig a // single horizontal tunnel to connect them; otherwise, we need to dig an 'L' shapped corridor to connect them. int minOverlappingY = Math.Max(leftRegion.BoundingRect.Top, rightRegion.BoundingRect.Top); int maxOverlappingY = Math.Min(leftRegion.BoundingRect.Bottom, rightRegion.BoundingRect.Bottom); if (maxOverlappingY - minOverlappingY >= 3) { // The regions overlap; we can dig a single horizontal corridor to connect them // Determine the range of Y axis values that we can dig at in order to connect the regions int corridorY = minOverlappingY + 1 + Rand.Next(maxOverlappingY - minOverlappingY - 2); digger.Dig(leftRegion.BoundingRect.Right, corridorY, Direction.Left, 0, true); digger.Dig(leftRegion.BoundingRect.Right + 1, corridorY, Direction.Right, rightRegion.BoundingRect.Left - (leftRegion.BoundingRect.Right + 1), true); } else { // They don't overlap enough; dig an 'L' shaped corridor to connect them. int tunnelMeetX, tunnelMeetY; if (leftRegion.BoundingRect.Top > rightRegion.BoundingRect.Top) { // Left region's bounding rect is below the Right region's bound rect. // _____ // X____| | // | | R | // | |___| // __|__ // | | // | L | // |___| tunnelMeetX = RandomValueBetween(leftRegion.BoundingRect.Left + 1, leftRegion.BoundingRect.Right); tunnelMeetY = RandomValueBetween(rightRegion.BoundingRect.Top + 1, Math.Min(rightRegion.BoundingRect.Bottom - 1, leftRegion.BoundingRect.Top)); digger.DigDownRightCorridor(tunnelMeetX, tunnelMeetY, rightRegion.BoundingRect.Left, leftRegion.BoundingRect.Top); } else { // Left child region's bounding rect is above the Right child region's bound rect. // _____ // | |____X // | L | | // |___| | // __|__ // | | // | R | // |___| tunnelMeetX = RandomValueBetween(rightRegion.BoundingRect.Left + 1, rightRegion.BoundingRect.Right); tunnelMeetY = RandomValueBetween(leftRegion.BoundingRect.Top + 1, Math.Min(leftRegion.BoundingRect.Bottom - 1, rightRegion.BoundingRect.Top)); digger.DigDownLeftLCorridor(tunnelMeetX, tunnelMeetY, leftRegion.BoundingRect.Right, rightRegion.BoundingRect.Top); } } } }