public void PartitionAround(Rectangle boundingRect) { float startX = (float)boundingRect.Left / Map.MapWidth; float startY = (float)boundingRect.Top / Map.MapHeight; float endX = (float)boundingRect.Right/ Map.MapWidth; float endY = (float)boundingRect.Bottom/ Map.MapHeight; // Create partitions around the carved out space, and don't partition the carved out space further // Here is how we create the partitions around the carved out space (marked with " XX "). The #s // represent the splits... // ________________________ // | | // | | // | | // |____1_________________| // | | | | // | | XX 4 | // | |____|___3____| // | | | // | 2 | // | | | // |________|_____________| // Do first split (#1) horizontally along the top edge of the carved out space this.SplitOrientation = Orientation.Vertical; this.SplitLocation = startX; if (startY == RegionEdges.Top) LeftChild = null; // Carved out partition abuts the TopEdge, so no need to create a 'Left' part else { LeftChild = new DungeonBSPNode(RegionEdges.Left, RegionEdges.Top, RegionEdges.Right, startY); if (WeShouldSplit(startY - RegionEdges.Top)) LeftChild.Partition(); } RightChild = new DungeonBSPNode(RegionEdges.Left, startY, RegionEdges.Right, RegionEdges.Bottom); // Do second split (#2) vertically along the left edge of the carved out space RightChild.SplitOrientation = Orientation.Horizontal; RightChild.SplitLocation = startY; if (startX == RegionEdges.Left) RightChild.LeftChild = null; // Carved out partition abuts the LeftEdge, so no need to create a 'Left' part else { RightChild.LeftChild = new DungeonBSPNode(RegionEdges.Left, startY, startX, RegionEdges.Bottom); if (WeShouldSplit(startX - RegionEdges.Left)) RightChild.LeftChild.Partition(); } RightChild.RightChild = new DungeonBSPNode(startX, startY, RegionEdges.Right, RegionEdges.Bottom); // Do third split (#3) horizontally along the bottom edge of the carved out space RightChild.RightChild.SplitOrientation = Orientation.Vertical; RightChild.RightChild.SplitLocation = endY; if (RegionEdges.Bottom == endY) RightChild.RightChild.RightChild = null; // Carved out partition abuts the BottomEdge, so no need to create a 'Right' part else { RightChild.RightChild.RightChild = new DungeonBSPNode(startX, endY, RegionEdges.Right, RegionEdges.Bottom); if (WeShouldSplit(RegionEdges.Bottom - endY)) RightChild.RightChild.RightChild.Partition(); } RightChild.RightChild.LeftChild = new DungeonBSPNode(startX, startY, RegionEdges.Right, endY); // Do fourth split (#4) vertically along the right edge of the carved out space RightChild.RightChild.LeftChild.SplitOrientation = Orientation.Horizontal; RightChild.RightChild.LeftChild.SplitLocation = endX; if (RegionEdges.Right == endX) // Carved out partition abuts the RightEdge, so no need to create a 'Right' part RightChild.RightChild.LeftChild.RightChild = null; else { RightChild.RightChild.LeftChild.RightChild = new DungeonBSPNode(endX, startY, RegionEdges.Right, endY); if (WeShouldSplit(RegionEdges.Right - endX)) RightChild.RightChild.LeftChild.RightChild.Partition(); } // Finally, partition the carved out space (and don't further partition it) RightChild.RightChild.LeftChild.LeftChild = new DungeonBSPNode(startX, startY, endX, endY); // Mark that the carved-out partition is pre-populated (don't add a room to it) RightChild.RightChild.LeftChild.LeftChild.RoomBuilt = true; RightChild.RightChild.LeftChild.LeftChild.BoundingRect = boundingRect; }
private DungeonBSPNode PartitionDungeon() { // Initialize a few variables. These'll eventually be removed DungeonBSPNode.Map = TargetMap; // I eventually want to share the random # generator across all objects, so that all that's // necessary to completely recreate a particular run is the initial Seed & the list of user inputs/ DungeonBSPNode.rand = TargetMap.rand; // Create the root node; it covers the entire space (0.0,0.0) - (1.0,1.0) DungeonBSPNode rootNode = new DungeonBSPNode(0.0f, 0.0f, 1.0f, 1.0f); // Add Special Room before partitioning /* if (false) // place special room { Room prefabRoom = Room.LoadRandom(); int xSpecialRoomStart = 20; int ySpecialRoomStart = 20; prefabRoom.BoundingRect = new Rectangle(prefabRoom.BoundingRect.Left + xSpecialRoomStart, prefabRoom.BoundingRect.Top + ySpecialRoomStart, prefabRoom.BoundingRect.Width, prefabRoom.BoundingRect.Height); // Add the room to the Map. TargetMap.PaintRoom(xSpecialRoomStart, ySpecialRoomStart, prefabRoom.RoomCells); // Partition the remaining dungeon layer around the placed room rootNode.PartitionAround(prefabRoom.BoundingRect); } else { */ // No special room rootNode.Partition(); // } return rootNode; }
/// <summary> /// Partitions (splits) this node into two halves, and then creates child nodes for /// each half and recursively partitions both of them (if they are not 'too small'). /// </summary> public void Partition() { // Choose the axis along which we'll partition (split) this node. If this is a very // narrow node in one axis, then favor the other axis in order to minimize long corridor-like rooms. if (RegionEdges.Width / RegionEdges.Height > MaxPartitionSizeRatio) SplitOrientation = Orientation.Horizontal; else if (RegionEdges.Height / RegionEdges.Width > MaxPartitionSizeRatio) SplitOrientation = Orientation.Vertical; else SplitOrientation = (rand.Next(2) == 1) ? Orientation.Horizontal : Orientation.Vertical; // Split the Node. if (SplitOrientation == Orientation.Horizontal) { // Pick the location along the XAxis (between the LeftEdge and RightEdge) at which we will split. SplitLocation = RegionEdges.Left + HomogenizedRandomValue() * RegionEdges.Width; // Create our two child nodes LeftChild = new DungeonBSPNode(RegionEdges.Left, RegionEdges.Top, SplitLocation, RegionEdges.Bottom); RightChild = new DungeonBSPNode(SplitLocation, RegionEdges.Top, RegionEdges.Right, RegionEdges.Bottom); SetDebugNames(); // Partition child nodes if either is not yet too small if (WeShouldSplit(SplitLocation - RegionEdges.Left)) LeftChild.Partition(); if (WeShouldSplit(RegionEdges.Right - SplitLocation)) RightChild.Partition(); } else // Vertical split { // Pick the location along the YAxis (between the TopEdge and BottomEdge) at which we will split. SplitLocation = RegionEdges.Top + HomogenizedRandomValue() * RegionEdges.Height; // Create our two (Left = upper and Right = lower) child nodes LeftChild = new DungeonBSPNode(RegionEdges.Left, RegionEdges.Top, RegionEdges.Right, SplitLocation); RightChild = new DungeonBSPNode(RegionEdges.Left, SplitLocation, RegionEdges.Right, RegionEdges.Bottom); SetDebugNames(); // Partition child nodes if either is not yet too small if (WeShouldSplit(SplitLocation - RegionEdges.Top)) LeftChild.Partition(); if (WeShouldSplit(RegionEdges.Bottom - SplitLocation)) RightChild.Partition(); } }