private bool RegionOverlapsRoom(int x, int y, int h, int w, MapRoom room) { if (room.bounds.x + room.bounds.w < x) return false; if (x + w < room.bounds.x) return false; if (room.bounds.y + room.bounds.h < y) return false; if (y + h < room.bounds.y) return false; return true; }
private bool RegionOverlapsRoom(int x, int y, int h, int w, MapRoom room) { if (room.bounds.x + room.bounds.w < x) { return(false); } if (x + w < room.bounds.x) { return(false); } if (room.bounds.y + room.bounds.h < y) { return(false); } if (y + h < room.bounds.y) { return(false); } return(true); }
// pixel types: // [0] = wall // [1] = floor // [2] = door // >2 = other sorts of wall // not on list = impenetrable // custom params: // none; skips rooms with doNotConnect set to true public override List <MapRoom> Run(int[][] map, MapRectangle fillRegion, List <MapRoom> roomsToInclude) { bool debug = false; if (debug) { Console.WriteLine("DCMG start, " + roomsToInclude.Count + " rooms"); } int corridorPixelType = 1234567; // pass 1 : get all the rooms connected to each other List <int> alreadyConnectedRoomIndices = new List <int>(); for (int i = 0; (i < roomsToInclude.Count) && (alreadyConnectedRoomIndices.Count < 1); i++) { if (!roomsToInclude[i].doNotConnect) { alreadyConnectedRoomIndices.Add(i); if (debug) { Console.WriteLine("DCMG to connect room " + i); } } } if (alreadyConnectedRoomIndices.Count < 1) { // none of the rooms want to be hooked up to each other return(roomsToInclude); } // distanceMap = -1 for impassable squares int[][] distanceMap = Allocate2DIntArray(fillRegion.w, fillRegion.h); // fromDirectionMap = -1 for unvisited, 0 1 2 3 = from N S E W int[][] fromDirectionMap = Allocate2DIntArray(fillRegion.w, fillRegion.h); // set true for the goal squares of a search bool[][] goalMap = Allocate2DBoolArray(fillRegion.w, fillRegion.h); // > 0 for squares that are expensive to step into int[][] extraCostMap = Allocate2DIntArray(fillRegion.w, fillRegion.h); if (intoPixelCostPenalty != null) { for (int i = 0; i < fillRegion.w; i++) { for (int j = 0; j < fillRegion.h; j++) { int pixel = map[fillRegion.x + i][fillRegion.y + j]; if (pixel >= 0 && pixel < intoPixelCostPenalty.Length) { extraCostMap[i][j] = intoPixelCostPenalty[pixel]; } } } } for (int i = alreadyConnectedRoomIndices[0] + 1; i < roomsToInclude.Count; i++) { MapRoom thisRoom = roomsToInclude[i]; if (!thisRoom.doNotConnect) { if (debug) { Console.WriteLine("DCMG try to connect " + i + " to net"); } int bestDoorIndex = -1; int bestDoorDistanceSquared = 0; int bestTargetRoomIndex = -1; for (int j = 0; j < thisRoom.doors.Count; j++) { for (int k = 0; k < alreadyConnectedRoomIndices.Count; k++) { int testRoomIndex = alreadyConnectedRoomIndices[k]; MapRoom r2 = roomsToInclude[testRoomIndex]; int dx = thisRoom.doors[j].x - r2.bounds.xCenter; int dy = thisRoom.doors[j].y - r2.bounds.yCenter; int testDistanceSquared = dx * dx + dy * dy; if (bestTargetRoomIndex == -1 || testDistanceSquared < bestDoorDistanceSquared) { bestTargetRoomIndex = testRoomIndex; bestDoorIndex = j; bestDoorDistanceSquared = testDistanceSquared; if (debug) { Console.WriteLine(" new closest door is " + j + " to room " + testRoomIndex + " from room " + i); } } } } if (bestDoorIndex != -1) { // run a BFS corridor from door bestDoor of // roomsToInclude[i] to any existing corridor or // any door of roomsToInclude[bestTargetRoomIndex] Clear2DIntArray(fromDirectionMap, -1); // unvisited // set all of the rooms interiors and walls to // impassable Clear2DIntArray(distanceMap, 100000000); foreach (MapRoom r in roomsToInclude) { for (int j = 1; j < r.bounds.w - 1; j++) { int dx = r.bounds.x + j - fillRegion.x; for (int k = 1; k < r.bounds.h - 1; k++) { int dy = r.bounds.y + k - fillRegion.y; distanceMap[dx][dy] = -1; } } } // set up the goals Clear2DBoolArray(goalMap); MapRoom targetRoom = roomsToInclude[ bestTargetRoomIndex]; for (int j = 1; j < targetRoom.bounds.w - 1; j++) { for (int k = 1; k < targetRoom.bounds.h - 1; k++) { goalMap[j + targetRoom.bounds.x - fillRegion.x][ k + targetRoom.bounds.y - fillRegion.y] = true; } } for (int j = 0; j < targetRoom.doors.Count; j++) { int dx = targetRoom.doors[j].x - fillRegion.x; int dy = targetRoom.doors[j].y - fillRegion.y; goalMap[dx][dy] = true; distanceMap[dx][dy] = 1000000; } // also load the existing cooridors into the goal map for (int j = 0; j < fillRegion.w; j++) { for (int k = 0; k < fillRegion.h; k++) { if (map[fillRegion.x + j][fillRegion.y + k] == corridorPixelType) { goalMap[j][k] = true; } } } bool success = ExtendBFSCorridor(goalMap, distanceMap, extraCostMap, fromDirectionMap, thisRoom.doors[bestDoorIndex].x - fillRegion.x, thisRoom.doors[bestDoorIndex].y - fillRegion.y, map, fillRegion, corridorPixelType, debug); if (success) { alreadyConnectedRoomIndices.Add(i); } if (debug) { Console.WriteLine(" ran route from door " + bestDoorIndex + " success = " + success); } } } } // convert corridorPixelType to pixelTypes[1] SearchAndReplace2DIntArray(map, corridorPixelType, pixelTypes[1]); return(roomsToInclude); }
// pixel types: // [0] = wall // [1] = floor // [2] = door // custom params: // none public override List <MapRoom> Run(int[][] map, MapRectangle fillRegion, List <MapRoom> roomsToInclude) { List <MapRoom> generatedRooms = new List <MapRoom>(); // generate the rooms int mapArea = map[0].Length * map.Length; int typicalRoomArea = (minSide + maxSide) * (minSide + maxSide) / 4; int nRooms = mapArea * openPercentage / typicalRoomArea; for (int i = 0; i < nRooms; i++) { int maxPlacementTries = 10; bool placed = false; int width = NextRandom(minSide, maxSide + 1); int height = NextRandom(minSide, maxSide + 1); if (width < fillRegion.w && height < fillRegion.h) { int x0 = 0, y0 = 0; for (int j = 0; (j < maxPlacementTries) && (!placed); j++) { x0 = NextRandom(0, fillRegion.w - width); y0 = NextRandom(0, fillRegion.h - height); placed = true; for (int k = 0; k < roomsToInclude.Count && placed; k++) { if (RegionOverlapsRoom(x0, y0, height, width, roomsToInclude[k])) { placed = false; } } for (int k = 0; k < generatedRooms.Count && placed; k++) { if (RegionOverlapsRoom(x0, y0, height, width, generatedRooms[k])) { placed = false; } } } if (placed) { generatedRooms.Add(new MapRoom(new MapRectangle( x0, y0, width, height))); } } } // add doors to generatedRooms for (int i = 0; i < generatedRooms.Count; i++) { int nDoors = NextRandom(1, maxDoorsPerRoom + 1); MapRoom r = generatedRooms[i]; for (int j = 0; j < nDoors; j++) { int side = NextRandom(0, 4); int offset = NextRandom(1, ((side == 0 || side == 2) ? r.bounds.w : r.bounds.h) - 1); r.doors.Add(new MapRoomDoor(side, offset, r)); } // clean out any duplicated doors for (int j = r.doors.Count - 1; j > 0; j--) { bool dupe = false; for (int k = 0; k < j; k++) { if (r.doors[j].side == r.doors[k].side && r.doors[j].offset == r.doors[k].offset) { dupe = true; } } if (dupe) { r.doors.RemoveAt(j); } } } // now set the map tiles for doors, walls, and floors for (int i = 0; i < generatedRooms.Count; i++) { MapRoom r = generatedRooms[i]; for (int j = r.bounds.x; j < r.bounds.x + r.bounds.w; j++) { for (int k = r.bounds.y; k < r.bounds.y + r.bounds.h; k++) { bool isBorder = (j == r.bounds.x) || (j == r.bounds.x + r.bounds.w - 1) || (k == r.bounds.y) || (k == r.bounds.y + r.bounds.h - 1); map[j][k] = pixelTypes[isBorder ? 0 : 1]; } } for (int j = 0; j < r.doors.Count; j++) { int x = r.bounds.x, y = r.bounds.y; switch (r.doors[j].side) { case 0: // N, offset from W x += r.doors[j].offset; break; case 1: // E, offset from N x += r.bounds.w - 1; y += r.doors[j].offset; break; case 2: // S, offset from W x += r.doors[j].offset; y += r.bounds.h - 1; break; case 3: // W, offset from N y += r.doors[j].offset; break; } map[x][y] = pixelTypes[2]; } } return(generatedRooms); }
public MapRoomDoor(int side, int offset, MapRoom parent) { this.side = side; this.offset = offset; this.parent = parent; }