public override void Generate() { // Create BSP tree to partition floor randomly (but w/o overlaps) partitionedTree = PartitionDungeon(); // Now that we have partitioned the dungeon into non-overlapping regions, create rooms in each "leaf" region // and create corridors between each non-leaf region. // We do this by telling the partitioned dungeon tree to find all nodes from the bottom up at each level. On leaf // nodes (those at the bottom of the tree which have not been partitioned into smaller regions) we call our // "AddRoom" function with each leaf node's coordinates. On non-leaf nodes, we call our "AddCorridor" function // Thanks to Jice for the overview (http://jice.nospam.googlepages.com/basicdungeongeneration). // Variety is the spice of life; mix things up a bit. RoomGeneratorDelegate roomGenerator; // Choose square or round rooms (or mix). In future, have more complex room generators. /* switch (Rand.Next(3)) { case 0: roomGenerator = new RoomGeneratorDelegate(SquareRoomGenerator); break; case 1: roomGenerator = new RoomGeneratorDelegate(RoundRoomGenerator); break; default: roomGenerator = new RoomGeneratorDelegate(RandomShapeRoomGenerator); break; } */ roomGenerator = new RoomGeneratorDelegate(SquareRoomGenerator); // Choose a process by which we connect rooms if (Rand.Next(2) == 1) { // Do a BSP-based inverted breadth order search, creating rooms and corridors as we go. // Semi-"intelligent" approach, in that it gaurantees connections between all rooms and doesn't create "odd" rooms // or dead-end corridors partitionedTree.BottomsUpByLevelEnumerate(new RoomGeneratorDelegate(roomGenerator), new CorridorGeneratorDelegate(DefaultCorridorGenerator)); } else { // Mimic DCSS's approach - get a list of rooms; randomize it; then dig corridors between them all, going right through rooms as we go. // This approach generates odd (eg doors in the middle of nowhere), but cool looking layouts. // 1. Get the list of regions with rooms in them // 2. Randomize the list (so we don't connect too many rooms that are right next to each other; counter-intuitive, I know) // 3. Connect the lists in order (connect #0 to #1, connect #1 to #2, etc). brute force it. // Generate the list of rooms. Don't pass a corridor generator since we're handling it ourselves post-processing. partitionedTree.BottomsUpByLevelEnumerate(new RoomGeneratorDelegate(roomGenerator), null); // Get the list of rooms List<DungeonBSPNode> roomRegions = partitionedTree.GetRoomRegions(); // Randomize the list order (Go go Gadget-C#!) roomRegions.Sort(RandomNodeComparer); // Connect the room regions in the newly randomized list order DungeonBSPNode previousRoom = null; foreach (DungeonBSPNode currentRoom in roomRegions) { if (previousRoom != null) BruteForceConnectRooms(previousRoom, currentRoom); previousRoom = currentRoom; } } }
public void BottomsUpByLevelEnumerate(RoomGeneratorDelegate roomGenerator, CorridorGeneratorDelegate corridorGenerator) { Stack stack1 = new Stack(); Stack stack2 = new Stack(); stack1.Push(this); while (stack1.Count > 0) { DungeonBSPNode currentNode = (DungeonBSPNode)stack1.Pop(); stack2.Push(currentNode); if (currentNode.LeftChild != null) stack1.Push(currentNode.LeftChild); if (currentNode.RightChild != null) stack1.Push(currentNode.RightChild); } while (stack2.Count > 0) { DungeonBSPNode currentNode = (DungeonBSPNode)stack2.Pop(); if (currentNode.LeftChild == null && currentNode.RightChild == null) { // Leaf node - create a room if (!currentNode.RoomBuilt && roomGenerator != null) roomGenerator(currentNode); } else { // non-leaf node; create corridor if (corridorGenerator != null && (currentNode.LeftChild.RoomBuilt || currentNode.RightChild.RoomBuilt)) corridorGenerator(currentNode); } } }