// returns a Path if there is one or null if not // default to allow diagonal steps public static Path BFSPath(int xStart, int yStart, int xEnd, int yEnd, CanStep stepFrom, CanStep stepTo, StepCost costFrom, DirectedStepCost costTo, MapRectangle limits) { return(BFSPath(xStart, yStart, xEnd, yEnd, stepFrom, stepTo, costFrom, costTo, limits, true)); }
// returns a Path if there is one or null if not // default to allow diagonal steps public static Path BFSPath(int xStart, int yStart, int xEnd, int yEnd, CanStep stepFrom, CanStep stepTo, StepCost costFrom, DirectedStepCost costTo, MapRectangle limits) { return BFSPath(xStart, yStart, xEnd, yEnd, stepFrom, stepTo, costFrom, costTo, limits, true); }
public static void CalculateBresenhamProductsToRectangle(int fromX, int fromY, int[][] map, MapRectangle rectangle, UpdateProductForSquare update, int startingProduct, int[][] outputMap) { CalculateBresenhamProductsToRectangle(fromX, fromY, map, rectangle, update, startingProduct, false, true, outputMap); }
public static void CalculateBresenhamProductsToRectangle(int fromX, int fromY, int[][] map, MapRectangle rectangle, UpdateProductForSquare update, int startingProduct, bool includeFirstSquare, bool includeLastSquare, int[][] outputMap) { // top and bottom edges for (int x = rectangle.x; x <= rectangle.x2; x++) { outputMap[fromX][fromY] = startingProduct; CalculateBresenhamProductSquareToSquare(fromX, fromY, x, rectangle.y, map, (previous, mapval, xs, ys) => { outputMap[xs][ys] = update(previous, mapval); return(outputMap[xs][ys]); }, startingProduct, includeFirstSquare, includeLastSquare); outputMap[fromX][fromY] = startingProduct; CalculateBresenhamProductSquareToSquare(fromX, fromY, x, rectangle.y2, map, (previous, mapval, xs, ys) => { outputMap[xs][ys] = update(previous, mapval); return(outputMap[xs][ys]); }, startingProduct, includeFirstSquare, includeLastSquare); } // right and left edges for (int y = rectangle.y + 1; y <= rectangle.y2 - 1; y++) { outputMap[fromX][fromY] = startingProduct; CalculateBresenhamProductSquareToSquare(fromX, fromY, rectangle.x, y, map, (previous, mapval, xs, ys) => { outputMap[xs][ys] = update(previous, mapval); return(outputMap[xs][ys]); }, startingProduct, includeFirstSquare, includeLastSquare); outputMap[fromX][fromY] = startingProduct; CalculateBresenhamProductSquareToSquare(fromX, fromY, rectangle.x2, y, map, (previous, mapval, xs, ys) => { outputMap[xs][ys] = update(previous, mapval); return(outputMap[xs][ys]); }, startingProduct, includeFirstSquare, includeLastSquare); } }
// pixel types: // [0] = outer wall // [1] = inner fill // custom params: // none public override List<MapRoom> Run(int[][] map, MapRectangle fillRegion, List<MapRoom> roomsToInclude) { bool[][] pixelIsProtected = BuildProtectedMap(roomsToInclude, map.Length, map[0].Length); for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (!pixelIsProtected[i][j]) { bool isBorder = (i == fillRegion.x || i == fillRegion.x2 || j == fillRegion.y || j == fillRegion.y2); map[i][j] = isBorder ? pixelTypes[1] : pixelTypes[0]; } } } return new List<MapRoom>(new MapRoom[0]); }
// pixel types: // [0] = outer wall // [1] = inner fill // custom params: // none public override List <MapRoom> Run(int[][] map, MapRectangle fillRegion, List <MapRoom> roomsToInclude) { bool[][] pixelIsProtected = BuildProtectedMap(roomsToInclude, map.Length, map[0].Length); for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (!pixelIsProtected[i][j]) { bool isBorder = (i == fillRegion.x || i == fillRegion.x2 || j == fillRegion.y || j == fillRegion.y2); map[i][j] = isBorder ? pixelTypes[1] : pixelTypes[0]; } } } return(new List <MapRoom>(new MapRoom[0])); }
public abstract List <MapRoom> Run(int[][] map, MapRectangle fillRegion, List <MapRoom> roomsToInclude);
public MapRoom(MapRectangle bounds) { this.bounds = bounds; this.doors = new List <MapRoomDoor>(); this.doNotConnect = false; }
// pixel types: // [0] = wall // [1] = floor /// [2] = door // custom params: // nLevels = max levels of subdivision // corridorWidth = top-level corridor width; drops by 1 at each // level below til it reaches 1 public override List <MapRoom> Run(int[][] map, MapRectangle fillRegion, List <MapRoom> roomsToInclude) { bool debug = false; bool[][] pixelIsProtected = BuildProtectedMap(roomsToInclude, map.Length, map[0].Length); for (int i = 0; i < fillRegion.w; i++) { for (int j = 0; j < fillRegion.h; j++) { if (!pixelIsProtected[i + fillRegion.x][j + fillRegion.y]) { map[i + fillRegion.x][j + fillRegion.y] = pixelTypes[1]; } } } List <MapRoom> rooms = BSPBlock(nLevels, corridorWidth, NextRandom(0, 2) == 1, pixelIsProtected, map, fillRegion); if (debug) { Console.WriteLine("Fill region " + fillRegion); } foreach (MapRoom room in rooms) { bool[] sideOk = new bool[] { true, true, true, true }; int nSidesOk = 4; if (debug) { Console.WriteLine("Room at " + room.bounds); } if (room.bounds.x == fillRegion.x) { if (debug) { Console.WriteLine(" W wall external"); } sideOk[3] = false; nSidesOk--; } if (room.bounds.y == fillRegion.y) { if (debug) { Console.WriteLine(" N wall external"); } sideOk[0] = false; nSidesOk--; } if (room.bounds.x2 == fillRegion.x2) { if (debug) { Console.WriteLine(" E wall external"); } sideOk[1] = false; nSidesOk--; } if (room.bounds.y2 == fillRegion.y2) { if (debug) { Console.WriteLine(" S wall external"); } sideOk[2] = false; nSidesOk--; } if (debug) { Console.WriteLine(" # doorable sides = " + nSidesOk); } if (nSidesOk > 0) { int sideOffset = NextRandom(0, nSidesOk); int side = 0; while (!sideOk[side] || sideOffset > 0) { if (sideOk[side]) { sideOffset--; } side++; } int offset = NextRandom(2, (((side % 2) == 0) ? room.bounds.w : room.bounds.h) - 2); if (debug) { Console.WriteLine(" door in side " + side + " offset " + offset); } MapRoomDoor door = new MapRoomDoor(side, offset, room); room.doors.Add(door); map[door.x][door.y] = pixelTypes[2]; if (debug) { Console.WriteLine(" door at " + door.x + ", " + door.y); } } } return(rooms); }
// returns a Path if there is one or null if not public static Path BFSPath(int xStart, int yStart, int xEnd, int yEnd, CanStep stepFrom, CanStep stepTo, StepCost costFrom, DirectedStepCost costTo, MapRectangle limits, bool allowDiagonalSteps) { bool debug = false; if (debug) { Console.WriteLine("BFS start"); } // update bestCost to hold the Dijkstra map if (bestCost == null || bestCost.Length < limits.w) { bestCost = new int[limits.w][]; visitedFrom = new eStep[limits.w][]; } if (bestCost[0] == null || bestCost[0].Length < limits.h) { for (int x = 0; x < limits.w; x++) { bestCost[x] = new int[limits.h]; visitedFrom[x] = new eStep[limits.h]; } } // clear bestCost to -1 = unvisited for (int x = 0; x < limits.w; x++) { for (int y = 0; y < limits.h; y++) { bestCost[x][y] = -1; } } // forward pass List<int> frontX = new List<int>(); List<int> frontY = new List<int>(); List<int> newFrontX = new List<int>(); List<int> newFrontY = new List<int>(); frontX.Add(xStart); frontY.Add(yStart); bestCost[xStart - limits.x][yStart - limits.y] = 0; bool done = false; while (!done) { if (debug) { Console.WriteLine("BFS new iteration, front size = " + frontX.Count); } newFrontX.Clear(); newFrontY.Clear(); done = true; for (int i = 0; i < frontX.Count; i++) { int baseCost = bestCost[frontX[i] - limits.x][ frontY[i] - limits.y]; if (costFrom != null) { baseCost += costFrom(frontX[i], frontY[i]); } if (stepFrom == null || stepFrom(frontX[i], frontY[i])) { for (int j = 0; j < 8; j += (allowDiagonalSteps ? 1 : 2)) { int xNew = frontX[i] + StepDX[j]; int yNew = frontY[i] + StepDY[j]; if (debug) { Console.WriteLine(" attempt step from " + frontX[i] + ", " + frontY[i] + " dir " + j + " delta = " + StepDX[j] + ", " + StepDY[j] + " to " + xNew + ", " + yNew); } if (xNew >= limits.x && yNew >= limits.y && xNew <= limits.x2 && yNew <= limits.y2 && (stepTo == null || stepTo(xNew, yNew))) { int newCost = baseCost; if (costTo != null) { newCost += costTo(xNew, yNew, (eStep)j); } int dx = xNew - limits.x; int dy = yNew - limits.y; int currentCost = bestCost[dx][dy]; if (currentCost == -1 || currentCost > newCost) { bestCost[dx][dy] = newCost; visitedFrom[dx][dy] = ReverseStep[ (int)j]; newFrontX.Add(xNew); newFrontY.Add(yNew); if (debug) { Console.WriteLine(" step to " + xNew + ", " + yNew + " new cost = " + newCost); } done = false; } } } } } if (!done) { List<int> swap = newFrontX; newFrontX = frontX; frontX = swap; swap = newFrontY; newFrontY = frontY; frontY = swap; } } if (bestCost[xEnd - limits.x][yEnd - limits.y] != -1) { // reverse pass and path gen int x = xEnd, y = yEnd; List<eStep> steps = new List<eStep>(); while (x != xStart || y != yStart) { eStep backStep = visitedFrom[x - limits.x][y - limits.y]; steps.Add(backStep); int dx = StepDX[(int)backStep]; int dy = StepDY[(int)backStep]; x += dx; y += dy; } Path solution = new Path(new eStep[steps.Count]); for (int i = 0; i < steps.Count; i++) { solution.Steps[i] = ReverseStep[(int)steps[steps.Count - i - 1]]; } return solution; } else { return null; // there is no path } }
// pixel types: // [0] = wall // [1] = floor /// [2] = door // custom params: // nLevels = max levels of subdivision // corridorWidth = top-level corridor width; drops by 1 at each // level below til it reaches 1 public override List<MapRoom> Run(int[][] map, MapRectangle fillRegion, List<MapRoom> roomsToInclude) { bool debug = false; bool[][] pixelIsProtected = BuildProtectedMap(roomsToInclude, map.Length, map[0].Length); for (int i = 0; i < fillRegion.w; i++) { for (int j = 0; j < fillRegion.h; j++) { if (!pixelIsProtected[i + fillRegion.x][j + fillRegion.y]) { map[i + fillRegion.x][j + fillRegion.y] = pixelTypes[1]; } } } List<MapRoom> rooms = BSPBlock(nLevels, corridorWidth, NextRandom(0, 2) == 1, pixelIsProtected, map, fillRegion); if (debug) { Console.WriteLine("Fill region " + fillRegion); } foreach (MapRoom room in rooms) { bool[] sideOk = new bool[] {true, true, true, true}; int nSidesOk = 4; if (debug) { Console.WriteLine("Room at " + room.bounds); } if (room.bounds.x == fillRegion.x) { if (debug) { Console.WriteLine(" W wall external"); } sideOk[3] = false; nSidesOk--; } if (room.bounds.y == fillRegion.y) { if (debug) { Console.WriteLine(" N wall external"); } sideOk[0] = false; nSidesOk--; } if (room.bounds.x2 == fillRegion.x2) { if (debug) { Console.WriteLine(" E wall external"); } sideOk[1] = false; nSidesOk--; } if (room.bounds.y2 == fillRegion.y2) { if (debug) { Console.WriteLine(" S wall external"); } sideOk[2] = false; nSidesOk--; } if (debug) { Console.WriteLine(" # doorable sides = " + nSidesOk); } if (nSidesOk > 0) { int sideOffset = NextRandom(0, nSidesOk); int side = 0; while (!sideOk[side] || sideOffset > 0) { if (sideOk[side]) sideOffset--; side++; } int offset = NextRandom(2, (((side % 2) == 0) ? room.bounds.w : room.bounds.h) - 2); if (debug) { Console.WriteLine(" door in side " + side + " offset " + offset); } MapRoomDoor door = new MapRoomDoor(side, offset, room); room.doors.Add(door); map[door.x][door.y] = pixelTypes[2]; if (debug) { Console.WriteLine(" door at " + door.x + ", " + door.y); } } } return rooms; }
public static int Main(String[] args) { ClearMapGenerator gen = new ClearMapGenerator(new int[] {0, 0}, MapCoordinate.GenerateRandom()); MapData mapdata = new MapData(40, 40); ClearMapGenerator gen2 = new ClearMapGenerator(new int[] {2, 1}, MapCoordinate.GenerateRandom()); gen2.Run(mapdata.grid, new MapRectangle(10, 10, 10, 10), null); List<MapRoom> blockedList = new List<MapRoom>(); MapRectangle fullArea = new MapRectangle(0, 0, 40, 40); blockedList.Add(new MapRoom(new MapRectangle(10, 10, 10, 10))); gen.Run(mapdata.grid, fullArea, blockedList); if (args.Length == 0) { Console.WriteLine("Specify -cave, -dungeon, or -office"); return 0; } else if (args[0] == "-office") { gen.Run(mapdata.grid, fullArea, null); BSPBuildingMapGenerator bsp = new BSPBuildingMapGenerator( new int[] {0, 1, 7}, MapCoordinate.GenerateRandom(), 4, 3, 2); MapRectangle borderedArea = new MapRectangle(1, 1, 38, 38); bsp.Run(mapdata.grid, borderedArea, null); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '.'); mapdata.AddSpaceType(glyph: 'O'); mapdata.AddSpaceType(glyph: '*'); mapdata.AddSpaceType(glyph: '~'); mapdata.AddSpaceType(glyph: 'X'); mapdata.AddSpaceType(glyph: ' '); mapdata.AddSpaceType(glyph: '+'); } else if (args[0] == "-dungeon") { DungeonRoomMapGenerator drmg = new DungeonRoomMapGenerator(new int[] {5, 6, 7}, MapCoordinate.GenerateRandom(), 5, 12, 10, 3); List<MapRoom> allRooms = drmg.Run(mapdata.grid, fullArea, blockedList); DungeonCorridorMapGenerator dcmg = new DungeonCorridorMapGenerator( new int[] {5, 6, 7}, MapCoordinate.GenerateRandom(), 2, new int[] {0, 100000, 100000, 0, 0, 100000, 0, 0}); dcmg.Run(mapdata.grid, fullArea, allRooms); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '*'); mapdata.AddSpaceType(glyph: '~'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: ' '); mapdata.AddSpaceType(glyph: '+'); } else if (args[0] == "-cave") { CADecayMapGenerator cad = new CADecayMapGenerator(new int[] {0, 1}, MapCoordinate.GenerateRandom(), 10, 20, 5, 10); // add this to not get random caves // cad.UseCoordinateBasedRandom(); cad.Run(mapdata.grid, fullArea, blockedList); CAGrowthMapGenerator cag1 = new CAGrowthMapGenerator(new int[] {3, 1}, MapCoordinate.GenerateRandom(), 50, 2, 20); cag1.Run(mapdata.grid, fullArea, blockedList); CAGrowthMapGenerator cag2 = new CAGrowthMapGenerator(new int[] {4, 1, 2}, MapCoordinate.GenerateRandom(), 200, 8, 20); cag2.Run(mapdata.grid, fullArea, blockedList); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '.'); mapdata.AddSpaceType(glyph: 'O'); mapdata.AddSpaceType(glyph: '*'); mapdata.AddSpaceType(glyph: '~'); mapdata.AddSpaceType(glyph: 'X'); mapdata.AddSpaceType(glyph: ' '); mapdata.AddSpaceType(glyph: '+'); } else if (args[0] == "-line") { Path path = PathUtils.GetBresenhamPath(0, 1, 6, 4, null); Console.WriteLine("Path from 0, 1 to 6, 4"); PathUtils.PrintPath(path, 0, 1); PathUtils.GetBresenhamPath(-3, 1, -4, 9, path); Console.WriteLine("Path from -3, 1 to -4, 9"); PathUtils.PrintPath(path, -3, 1); gen = new ClearMapGenerator(new int[] {1, 1}, MapCoordinate.GenerateRandom()); fullArea = new MapRectangle(0, 0, 40, 40); mapdata = new MapData(40, 40); gen.Run(mapdata.grid, fullArea, null); int length = PathUtils.CalculateBresenhamProductSquareToSquare( 0, 1, 6, 4, mapdata.grid, (x, y) => x + y, 0); Console.WriteLine("Length (0, 1) -> (6, 4) in steps = " + length); MapData distance = new MapData(40, 40); PathUtils.CalculateBresenhamProductsToRectangle(5, 5, mapdata.grid, fullArea, (x, y) => x + y, 0, distance.grid); for (int i = 0; i < 20; i++) { Console.WriteLine("3 " + i + " dist = " + distance.grid[3][i]); } return 0; } else if (args[0] == "-bfs") { DungeonRoomMapGenerator drmg = new DungeonRoomMapGenerator(new int[] {5, 6, 7}, MapCoordinate.GenerateRandom(), 5, 12, 10, 3); List<MapRoom> allRooms = drmg.Run(mapdata.grid, fullArea, blockedList); DungeonCorridorMapGenerator dcmg = new DungeonCorridorMapGenerator( new int[] {5, 6, 7}, MapCoordinate.GenerateRandom(), 2, new int[] {0, 100000, 100000, 0, 0, 100000, 0, 0}); dcmg.Run(mapdata.grid, fullArea, allRooms); int xStart = allRooms[0].bounds.xCenter; int yStart = allRooms[0].bounds.yCenter; int xEnd = allRooms[1].bounds.xCenter; int yEnd = allRooms[1].bounds.yCenter; Path path = PathUtils.BFSPath(xStart, yStart, xEnd, yEnd, null, (x, y) => (mapdata.grid[x][y] >= 6), null, (x, y, d) => ((((int)d) % 2) == 1 ? 140 : 100), fullArea); if (path != null) { int[][] pathSquares = PathUtils.UnrollPath(path, xStart, yStart); for (int i = 0; i < pathSquares.Length; i++) { mapdata.grid[pathSquares[i][0]][pathSquares[i][1]] = 8; } } mapdata.grid[xStart][yStart] = 9; mapdata.grid[xEnd][yEnd] = 10; mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '*'); mapdata.AddSpaceType(glyph: '~'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: ' '); mapdata.AddSpaceType(glyph: '+'); mapdata.AddSpaceType(glyph: 'v'); mapdata.AddSpaceType(glyph: 'S'); mapdata.AddSpaceType(glyph: 'E'); } else { Console.WriteLine("Specify -cave, -dungeon, or -office"); return 0; } DisplayMap(mapdata); return 0; }
public override List <MapRoom> Run(int[][] map, MapRectangle fillRegion, List <MapRoom> roomsToInclude) { bool[][] pixelIsProtected = BuildProtectedMap(roomsToInclude, map.Length, map[0].Length); // make a map of which pixels are open for growth int nOpen = 0; bool[][] open = new bool[fillRegion.w][]; for (int i = fillRegion.x; i <= fillRegion.x2; i++) { open[i] = new bool[fillRegion.h]; for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (!pixelIsProtected[i][j]) { for (int k = 0; k < openGrowthPixels.Length; k++) { if (map[i][j] == openGrowthPixels[k]) { open[i - fillRegion.x][j - fillRegion.y] = true; nOpen++; } } } } } // put in the seeds int n = nOpen / seedPointInverseDensity; for (int i = 0; i < n; i++) { int offset = NextRandom(0, nOpen); for (int j = 0; (j < fillRegion.w) && (offset > 0); j++) { for (int k = 0; k < fillRegion.h; k++) { if (open[j][k]) { offset--; if (offset == 0) { map[j + fillRegion.x][k + fillRegion.y] = newGrowthPixel; } } } } } for (int k = 0; k < numberOfGrowPasses; k++) { for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (map[i][j] != newGrowthPixel && open[i - fillRegion.x][j - fillRegion.y]) { int nNeighbors = 0; if (i > 0) { if (j > 0) { if (map[i - 1][j - 1] == newGrowthPixel) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i - 1][j + 1] == newGrowthPixel) { nNeighbors++; } } if (map[i - 1][j] == newGrowthPixel) { nNeighbors++; } } if (i < map.Length - 1) { if (j > 0) { if (map[i + 1][j - 1] == newGrowthPixel) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i + 1][j + 1] == newGrowthPixel) { nNeighbors++; } } if (map[i + 1][j] == newGrowthPixel) { nNeighbors++; } } if (j > 0) { if (map[i][j - 1] == newGrowthPixel) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i][j + 1] == newGrowthPixel) { nNeighbors++; } } int flipChance = nNeighbors * growthPercentPerGrownNeighbor; if (NextRandom(1, 101) < flipChance) { map[i][j] = -1; } } } } for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (map[i][j] == -1 && !pixelIsProtected[i][j]) { map[i][j] = newGrowthPixel; } } } } return(new List <MapRoom>(new MapRoom[0])); }
static public void Main () { //UI d = new VT100UI(); VT100UI d = new VT100UI(); // This is just a placeholder for (int x = 0; x < 80; x++) { d.DrawAt(x,3," ",0,0,0,0,0,64); } for (int x = 0; x < 80; x++) { d.DrawAt(x,22," ",0,0,0,0,0,64); } UIMapElement map_element = d.MapElement( x: 0, y: 4, h: 17 ); ClearMapGenerator gen = new ClearMapGenerator(new int[] {0, 0}, MapCoordinate.GenerateRandom()); map_element.map = new MapData(80,40); ClearMapGenerator gen2 = new ClearMapGenerator(new int[]{2, 1}, MapCoordinate.GenerateRandom()); gen2.Run(map_element.map.grid, new MapRectangle(10, 10, 10, 10), null); List<MapRoom> blockedList = new List<MapRoom>(); MapRectangle fullArea = new MapRectangle(0, 0, 80, 40); blockedList.Add(new MapRoom(new MapRectangle(10, 10, 10, 10))); gen.Run(map_element.map.grid, fullArea, blockedList); DungeonRoomMapGenerator drmg = new DungeonRoomMapGenerator(new int[] {5, 6, 7}, MapCoordinate.GenerateRandom(), 5, 12, 10, 3); List<MapRoom> allRooms = drmg.Run(map_element.map.grid, fullArea, blockedList); DungeonCorridorMapGenerator dcmg = new DungeonCorridorMapGenerator( new int[] {5, 6, 7}, MapCoordinate.GenerateRandom(), 2, new int[] {0, 100000, 100000, 0, 0, 100000, 0, 0}); dcmg.Run(map_element.map.grid, fullArea, allRooms); map_element.map.AddSpaceType(glyph: '#', r: 128, g: 128, b: 128); map_element.map.AddSpaceType(glyph: '#', r: 128, g: 128, b: 128); map_element.map.AddSpaceType(glyph: '#', r: 128, g: 128, b: 128); map_element.map.AddSpaceType(glyph: '*'); map_element.map.AddSpaceType(glyph: '~', r: 0, g: 32, b: 255); map_element.map.AddSpaceType(glyph: '#', r: 128, g: 128, b: 128); map_element.map.AddSpaceType(glyph: '.', r: 64, g: 64, b: 64); map_element.map.AddSpaceType(glyph: '+', r: 128, g: 64, b: 0); d.DrawAt(54,3," 5 targets in range ",255,255,192,0,0,0); d.DrawAt(74,3,"[T] ",192,192,255,0,0,0); d.DrawAt(58,22," Press for help ",255,255,192,0,0,0); d.DrawAt(65,22,"[?]",192,192,255,0,0,0); map_element.Draw(); d.DrawScreen(); }
public override List <MapRoom> Run(int[][] map, MapRectangle fillRegion, List <MapRoom> roomsToInclude) { bool[][] pixelIsProtected = BuildProtectedMap(roomsToInclude, map.Length, map[0].Length); // clear to solid for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (!pixelIsProtected[i][j]) { map[i][j] = pixelTypes[0]; } } } // put in the horizontal seed corridors int n = fillRegion.h / seedCorridorAverageSpacing; for (int i = 0; i < n; i++) { int l = NextRandom(seedCorridorAverageLength / 2, 3 * seedCorridorAverageLength / 2 + 1); int offset = 0; if (l >= fillRegion.w) { l = fillRegion.w; } else { offset = NextRandom(0, fillRegion.w - l + 1); } int crossOffset = NextRandom(fillRegion.y, fillRegion.y2 + 1); for (int j = offset; j < offset + l; j++) { if (!pixelIsProtected[j + fillRegion.x][crossOffset]) { map[j + fillRegion.x][crossOffset] = pixelTypes[1]; } } } // put in the vertical seed corridors n = fillRegion.w / seedCorridorAverageSpacing; for (int i = 0; i < n; i++) { int l = NextRandom(seedCorridorAverageLength / 2, 3 * seedCorridorAverageLength / 2 + 1); int offset = 0; if (l >= fillRegion.h) { l = fillRegion.h; } else { offset = NextRandom(0, fillRegion.h - l + 1); } int crossOffset = NextRandom(fillRegion.x, fillRegion.x2 + 1); for (int j = offset; j < offset + l; j++) { if (!pixelIsProtected[crossOffset][j + fillRegion.y]) { map[crossOffset][j + fillRegion.y] = pixelTypes[1]; } } } for (int k = 0; k < numberOfDecays; k++) { for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (map[i][j] == pixelTypes[0] && !pixelIsProtected[i][j]) { int nNeighbors = 0; if (i > 0) { if (j > 0) { if (map[i - 1][j - 1] == pixelTypes[1]) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i - 1][j + 1] == pixelTypes[1]) { nNeighbors++; } } if (map[i - 1][j] == pixelTypes[1]) { nNeighbors++; } } if (i < map.Length - 1) { if (j > 0) { if (map[i + 1][j - 1] == pixelTypes[1]) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i + 1][j + 1] == pixelTypes[1]) { nNeighbors++; } } if (map[i + 1][j] == pixelTypes[1]) { nNeighbors++; } } if (j > 0) { if (map[i][j - 1] == pixelTypes[1]) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i][j + 1] == pixelTypes[1]) { nNeighbors++; } } int flipChance = nNeighbors * decayPercentPerDecayedNeighbor; if (NextRandom(1, 101) < flipChance) { map[i][j] = -1; } } } } for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (map[i][j] == -1 && !pixelIsProtected[i][j]) { map[i][j] = pixelTypes[1]; } } } } return(new List <MapRoom>(new MapRoom[0])); }
// Use this for initialization void Start () { int player_x = 0; int player_y = 0; mapdata = new MapData(levelWidth,levelHeight); fullMapBounds = new MapRectangle(0, 0, levelWidth, levelHeight); ClearMapGenerator gen = new ClearMapGenerator(new int[] {0, 0}, MapCoordinate.GenerateRandom()); ClearMapGenerator gen2 = new ClearMapGenerator(new int[] {2, 1}, MapCoordinate.GenerateRandom()); gen2.Run(mapdata.grid, new MapRectangle(10, 10, 10, 10), null); List<MapRoom> blockedList = new List<MapRoom>(); MapRectangle fullArea = new MapRectangle(0, 0, 40, 40); blockedList.Add(new MapRoom(new MapRectangle(10, 10, 10, 10))); gen.Run(mapdata.grid, fullArea, blockedList); DungeonRoomMapGenerator drmg = new DungeonRoomMapGenerator(new int[] {5, 6, 7}, MapCoordinate.GenerateRandom(), 5, 12, 10, 3); List<MapRoom> allRooms = drmg.Run(mapdata.grid, fullArea, blockedList); DungeonCorridorMapGenerator dcmg = new DungeonCorridorMapGenerator( new int[] {5, 6, 7}, MapCoordinate.GenerateRandom(), 2, new int[] {0, 100000, 100000, 0, 0, 100000, 0, 0}); dcmg.Run(mapdata.grid, fullArea, allRooms); mapdata.AddSpaceType(glyph: '#', passable: false, transparent: false); mapdata.AddSpaceType(glyph: '#', passable: false, transparent: false); mapdata.AddSpaceType(glyph: '#', passable: false, transparent: false); mapdata.AddSpaceType(glyph: '*', passable: true, transparent: true); mapdata.AddSpaceType(glyph: '~', passable: true, transparent: true); mapdata.AddSpaceType(glyph: '#', passable: false, transparent: false); mapdata.AddSpaceType(glyph: ' ', passable: true, transparent: true); mapdata.AddSpaceType(glyph: '+', passable: true, transparent: false); bool[][] visibility_map = new bool[levelHeight][]; for (int i = 0; i < levelWidth; i++) { visibility_map[i] = new bool[levelWidth]; for (int j = 0; j < levelHeight; j++) { visibility_map[i][j] = false; bool keepLooping = true; for (int x = i-1; (keepLooping == true) && (x <= i+1); x++) { for (int y = j-1; (keepLooping == true) && (y <= j+1); y++) { if ( (x >= 0) && (x < levelWidth) && (y >= 0) && (y < levelHeight) && (mapdata.palette[mapdata.grid[x][y]].passable) ) { keepLooping = false; visibility_map[i][j] = true; } } } } } for (int i = 0; i < levelHeight; i++) { tileGrid.Add(new List<GameObject>()); subTileGrid.Add(new List<GameObject>()); for (int j = 0; j < levelWidth; j++) { // XXX this is profoundly dumb -- we're just assigning the player coords to the last passable square. But it's temporary. if (mapdata.palette[mapdata.grid[j][i]].passable) { player_x = j; player_y = i; } // special case for doors :( -- they need a floor. if (mapdata.grid[j][i] == 7) { var flr = Instantiate(this.tilePrefabs[6]) as GameObject; flr.transform.position = new Vector3(j, i, 1); subTileGrid[i].Add(flr); } else { subTileGrid[i].Add(null); } var o = Instantiate(this.tilePrefabs[mapdata.grid[j][i]]) as GameObject; o.transform.position = new Vector3(j, i, 0); var sts = o.GetComponent<ShapeTerrainScript>(); if (sts) { int surroundNum = 0; // 1: north if ( (i < 39) && (visibility_map[j][i+1]) && (! mapdata.palette[mapdata.grid[j][i+1]].passable) ) { surroundNum += 1; } // 2: east if ( (j < 39) && (visibility_map[j+1][i]) && (! mapdata.palette[mapdata.grid[j+1][i]].passable) ) { surroundNum += 2; } // 4: south if ( (i > 0) && (visibility_map[j][i-1]) && (! mapdata.palette[mapdata.grid[j][i-1]].passable) ) { surroundNum += 4; } // 8: west if ( (j > 0) && (visibility_map[j-1][i]) && (! mapdata.palette[mapdata.grid[j-1][i]].passable) ) { surroundNum += 8; } sts.SetSprite(surroundNum); if (! visibility_map[j][i]) o.GetComponent<SpriteRenderer>().enabled = false; } tileGrid[i].Add(o); } } this.player = Instantiate(this.playerPrefab) as GameObject; Vector3 pos = new Vector3(player_x, player_y, 0); this.player.transform.position = pos; this.player.transform.SetParent(transform); GameObject camera = Instantiate( cameraPrefab ); pos.z=-10; camera.transform.position = pos; camera.GetComponent<CameraScript>().target = this.player.transform; }
public abstract List<MapRoom> Run(int[][] map, MapRectangle fillRegion, List<MapRoom> roomsToInclude);
public MapRoom(MapRectangle bounds) { this.bounds = bounds; this.doors = new List<MapRoomDoor>(); this.doNotConnect = false; }
public static int Main(String[] args) { ClearMapGenerator gen = new ClearMapGenerator(new int[] { 0, 0 }, MapCoordinate.GenerateRandom()); MapData mapdata = new MapData(40, 40); ClearMapGenerator gen2 = new ClearMapGenerator(new int[] { 2, 1 }, MapCoordinate.GenerateRandom()); gen2.Run(mapdata.grid, new MapRectangle(10, 10, 10, 10), null); List <MapRoom> blockedList = new List <MapRoom>(); MapRectangle fullArea = new MapRectangle(0, 0, 40, 40); blockedList.Add(new MapRoom(new MapRectangle(10, 10, 10, 10))); gen.Run(mapdata.grid, fullArea, blockedList); if (args.Length == 0) { Console.WriteLine("Specify -cave, -dungeon, or -office"); return(0); } else if (args[0] == "-office") { gen.Run(mapdata.grid, fullArea, null); BSPBuildingMapGenerator bsp = new BSPBuildingMapGenerator( new int[] { 0, 1, 7 }, MapCoordinate.GenerateRandom(), 4, 3, 2); MapRectangle borderedArea = new MapRectangle(1, 1, 38, 38); bsp.Run(mapdata.grid, borderedArea, null); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '.'); mapdata.AddSpaceType(glyph: 'O'); mapdata.AddSpaceType(glyph: '*'); mapdata.AddSpaceType(glyph: '~'); mapdata.AddSpaceType(glyph: 'X'); mapdata.AddSpaceType(glyph: ' '); mapdata.AddSpaceType(glyph: '+'); } else if (args[0] == "-dungeon") { DungeonRoomMapGenerator drmg = new DungeonRoomMapGenerator(new int[] { 5, 6, 7 }, MapCoordinate.GenerateRandom(), 5, 12, 10, 3); List <MapRoom> allRooms = drmg.Run(mapdata.grid, fullArea, blockedList); DungeonCorridorMapGenerator dcmg = new DungeonCorridorMapGenerator( new int[] { 5, 6, 7 }, MapCoordinate.GenerateRandom(), 2, new int[] { 0, 100000, 100000, 0, 0, 100000, 0, 0 }); dcmg.Run(mapdata.grid, fullArea, allRooms); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '*'); mapdata.AddSpaceType(glyph: '~'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: ' '); mapdata.AddSpaceType(glyph: '+'); } else if (args[0] == "-cave") { CADecayMapGenerator cad = new CADecayMapGenerator(new int[] { 0, 1 }, MapCoordinate.GenerateRandom(), 10, 20, 5, 10); // add this to not get random caves // cad.UseCoordinateBasedRandom(); cad.Run(mapdata.grid, fullArea, blockedList); CAGrowthMapGenerator cag1 = new CAGrowthMapGenerator(new int[] { 3, 1 }, MapCoordinate.GenerateRandom(), 50, 2, 20); cag1.Run(mapdata.grid, fullArea, blockedList); CAGrowthMapGenerator cag2 = new CAGrowthMapGenerator(new int[] { 4, 1, 2 }, MapCoordinate.GenerateRandom(), 200, 8, 20); cag2.Run(mapdata.grid, fullArea, blockedList); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '.'); mapdata.AddSpaceType(glyph: 'O'); mapdata.AddSpaceType(glyph: '*'); mapdata.AddSpaceType(glyph: '~'); mapdata.AddSpaceType(glyph: 'X'); mapdata.AddSpaceType(glyph: ' '); mapdata.AddSpaceType(glyph: '+'); } else if (args[0] == "-line") { Path path = PathUtils.GetBresenhamPath(0, 1, 6, 4, null); Console.WriteLine("Path from 0, 1 to 6, 4"); PathUtils.PrintPath(path, 0, 1); PathUtils.GetBresenhamPath(-3, 1, -4, 9, path); Console.WriteLine("Path from -3, 1 to -4, 9"); PathUtils.PrintPath(path, -3, 1); gen = new ClearMapGenerator(new int[] { 1, 1 }, MapCoordinate.GenerateRandom()); fullArea = new MapRectangle(0, 0, 40, 40); mapdata = new MapData(40, 40); gen.Run(mapdata.grid, fullArea, null); int length = PathUtils.CalculateBresenhamProductSquareToSquare( 0, 1, 6, 4, mapdata.grid, (x, y) => x + y, 0); Console.WriteLine("Length (0, 1) -> (6, 4) in steps = " + length); MapData distance = new MapData(40, 40); PathUtils.CalculateBresenhamProductsToRectangle(5, 5, mapdata.grid, fullArea, (x, y) => x + y, 0, distance.grid); for (int i = 0; i < 20; i++) { Console.WriteLine("3 " + i + " dist = " + distance.grid[3][i]); } return(0); } else if (args[0] == "-bfs") { DungeonRoomMapGenerator drmg = new DungeonRoomMapGenerator(new int[] { 5, 6, 7 }, MapCoordinate.GenerateRandom(), 5, 12, 10, 3); List <MapRoom> allRooms = drmg.Run(mapdata.grid, fullArea, blockedList); DungeonCorridorMapGenerator dcmg = new DungeonCorridorMapGenerator( new int[] { 5, 6, 7 }, MapCoordinate.GenerateRandom(), 2, new int[] { 0, 100000, 100000, 0, 0, 100000, 0, 0 }); dcmg.Run(mapdata.grid, fullArea, allRooms); int xStart = allRooms[0].bounds.xCenter; int yStart = allRooms[0].bounds.yCenter; int xEnd = allRooms[1].bounds.xCenter; int yEnd = allRooms[1].bounds.yCenter; Path path = PathUtils.BFSPath(xStart, yStart, xEnd, yEnd, null, (x, y) => (mapdata.grid[x][y] >= 6), null, (x, y, d) => ((((int)d) % 2) == 1 ? 140 : 100), fullArea); if (path != null) { int[][] pathSquares = PathUtils.UnrollPath(path, xStart, yStart); for (int i = 0; i < pathSquares.Length; i++) { mapdata.grid[pathSquares[i][0]][pathSquares[i][1]] = 8; } } mapdata.grid[xStart][yStart] = 9; mapdata.grid[xEnd][yEnd] = 10; mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: '*'); mapdata.AddSpaceType(glyph: '~'); mapdata.AddSpaceType(glyph: '#'); mapdata.AddSpaceType(glyph: ' '); mapdata.AddSpaceType(glyph: '+'); mapdata.AddSpaceType(glyph: 'v'); mapdata.AddSpaceType(glyph: 'S'); mapdata.AddSpaceType(glyph: 'E'); } else { Console.WriteLine("Specify -cave, -dungeon, or -office"); return(0); } DisplayMap(mapdata); return(0); }
// 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); }
private bool ExtendBFSCorridor(bool[][] isGoal, int[][] bestDistance, int[][] extraCost, int[][] fromDirection, int x0, int y0, int[][] map, MapRectangle fillRegion, int open, bool debug) { bool debugVerbose = false; if (debug) { Console.WriteLine("BFS map with goal (O) and start (S) marked"); for (int i = 0; i < fillRegion.h; i++) { for (int j = 0; j < fillRegion.w; j++) { if (i == y0 && j == x0) { Console.Write("O"); } else if (bestDistance[i][j] == -1) { Console.Write("X"); } else if (isGoal[j][i]) { Console.Write("$"); } else { Console.Write("."); } } Console.WriteLine(""); } Console.WriteLine(""); } List <int> frontX = new List <int>(); List <int> frontY = new List <int>(); List <int> newFrontX = new List <int>(); List <int> newFrontY = new List <int>(); frontX.Add(x0); frontY.Add(y0); bestDistance[x0][y0] = 0; int bestGoalX = 0; int bestGoalY = 0; int bestGoalDistance = -1; bool done = true; do { // expand the existing front done = true; for (int i = 0; i < frontX.Count; i++) { if (debugVerbose) { Console.WriteLine("BFS: step from " + frontX[i] + ", " + frontY[i]); } for (int j = 0; j < 4; j++) { int to_x = frontX[i] + step_dx[j]; int to_y = frontY[i] + step_dy[j]; if (debugVerbose) { Console.WriteLine(" test step to " + to_x + ", " + to_y); } if (to_x >= 0 && to_x < isGoal.Length && to_y >= 0 && to_y < isGoal[0].Length && bestDistance[to_x][to_y] != -1) { bool stepIsTurn = false; if (frontX[i] != x0 || frontY[i] != y0) { stepIsTurn = (j != inverseDirection[ fromDirection[frontX[i]][frontY[i]]]); } int newDistance = bestDistance[frontX[i]][frontY[i]] + (stepIsTurn ? turnCostPenalty : 0) + extraCost[to_x][to_y] + 1; if (debugVerbose) { Console.WriteLine(" it's legit, turn = " + stepIsTurn + " cost = " + newDistance + " best cost so far = " + bestDistance[to_x][to_y]); } if (newDistance < bestDistance[to_x][to_y]) { done = false; bestDistance[to_x][to_y] = newDistance; fromDirection[to_x][to_y] = inverseDirection[j]; bool alreadyInNewFront = false; if (isGoal[to_x][to_y]) { if (bestGoalDistance == -1 || newDistance < bestGoalDistance) { bestGoalDistance = newDistance; bestGoalX = to_x; bestGoalY = to_y; } } for (int k = 0; k < newFrontX.Count; k++) { if (newFrontX[k] == to_x && newFrontY[k] == to_y) { alreadyInNewFront = true; } } if (!alreadyInNewFront) { newFrontX.Add(to_x); newFrontY.Add(to_y); } } } } } if (!done) { // swap the fronts if we are still advancing List <int> swapFrontX = frontX; List <int> swapFrontY = frontY; frontX = newFrontX; frontY = newFrontY; newFrontX = swapFrontX; newFrontY = swapFrontY; newFrontX.Clear(); newFrontY.Clear(); } }while (!done); if (debug) { Console.WriteLine(" BFS best goal distance = " + bestGoalDistance); } if (bestGoalDistance != -1) { // backward pass writing in the corridor int x = bestGoalX; int y = bestGoalY; while (x != x0 || y != y0) { if (x != bestGoalX || y != bestGoalY) { map[fillRegion.x + x][fillRegion.y + y] = open; if (debug) { Console.WriteLine(" corr at " + (fillRegion.x + x) + ", " + (fillRegion.y + y)); } } int fromDir = fromDirection[x][y]; x += step_dx[fromDir]; y += step_dy[fromDir]; } } return(bestGoalDistance != -1); }
private bool ExtendBFSCorridor(bool[][] isGoal, int[][] bestDistance, int[][] extraCost, int[][] fromDirection, int x0, int y0, int[][] map, MapRectangle fillRegion, int open, bool debug) { bool debugVerbose = false; if (debug) { Console.WriteLine("BFS map with goal (O) and start (S) marked"); for (int i = 0; i < fillRegion.h; i++) { for (int j = 0; j < fillRegion.w; j++) { if (i == y0 && j == x0) { Console.Write("O"); } else if (bestDistance[i][j] == -1) { Console.Write("X"); } else if (isGoal[j][i]) { Console.Write("$"); } else { Console.Write("."); } } Console.WriteLine(""); } Console.WriteLine(""); } List<int> frontX = new List<int>(); List<int> frontY = new List<int>(); List<int> newFrontX = new List<int>(); List<int> newFrontY = new List<int>(); frontX.Add(x0); frontY.Add(y0); bestDistance[x0][y0] = 0; int bestGoalX = 0; int bestGoalY = 0; int bestGoalDistance = -1; bool done = true; do { // expand the existing front done = true; for (int i = 0; i < frontX.Count; i++) { if (debugVerbose) { Console.WriteLine("BFS: step from " + frontX[i] + ", " + frontY[i]); } for (int j = 0; j < 4; j++) { int to_x = frontX[i] + step_dx[j]; int to_y = frontY[i] + step_dy[j]; if (debugVerbose) { Console.WriteLine(" test step to " + to_x + ", " + to_y); } if (to_x >= 0 && to_x < isGoal.Length && to_y >= 0 && to_y < isGoal[0].Length && bestDistance[to_x][to_y] != -1) { bool stepIsTurn = false; if (frontX[i] != x0 || frontY[i] != y0) { stepIsTurn = (j != inverseDirection[ fromDirection[frontX[i]][frontY[i]]]); } int newDistance = bestDistance[frontX[i]][frontY[i]] + (stepIsTurn ? turnCostPenalty : 0) + extraCost[to_x][to_y] + 1; if (debugVerbose) { Console.WriteLine(" it's legit, turn = " + stepIsTurn + " cost = " + newDistance + " best cost so far = " + bestDistance[to_x][to_y]); } if (newDistance < bestDistance[to_x][to_y]) { done = false; bestDistance[to_x][to_y] = newDistance; fromDirection[to_x][to_y] = inverseDirection[j]; bool alreadyInNewFront = false; if (isGoal[to_x][to_y]) { if (bestGoalDistance == -1 || newDistance < bestGoalDistance) { bestGoalDistance = newDistance; bestGoalX = to_x; bestGoalY = to_y; } } for (int k = 0; k < newFrontX.Count; k++) { if (newFrontX[k] == to_x && newFrontY[k] == to_y) { alreadyInNewFront = true; } } if (!alreadyInNewFront) { newFrontX.Add(to_x); newFrontY.Add(to_y); } } } } } if (!done) { // swap the fronts if we are still advancing List<int> swapFrontX = frontX; List<int> swapFrontY = frontY; frontX = newFrontX; frontY = newFrontY; newFrontX = swapFrontX; newFrontY = swapFrontY; newFrontX.Clear(); newFrontY.Clear(); } } while (!done); if (debug) { Console.WriteLine(" BFS best goal distance = " + bestGoalDistance); } if (bestGoalDistance != -1) { // backward pass writing in the corridor int x = bestGoalX; int y = bestGoalY; while (x != x0 || y != y0) { if (x != bestGoalX || y != bestGoalY) { map[fillRegion.x + x][fillRegion.y + y] = open; if (debug) { Console.WriteLine(" corr at " + (fillRegion.x + x) + ", " + (fillRegion.y + y)); } } int fromDir = fromDirection[x][y]; x += step_dx[fromDir]; y += step_dy[fromDir]; } } return (bestGoalDistance != -1); }
public override List<MapRoom> Run(int[][] map, MapRectangle fillRegion, List<MapRoom> roomsToInclude) { bool[][] pixelIsProtected = BuildProtectedMap(roomsToInclude, map.Length, map[0].Length); // make a map of which pixels are open for growth int nOpen = 0; bool[][] open = new bool[fillRegion.w][]; for (int i = fillRegion.x; i <= fillRegion.x2; i++) { open[i] = new bool[fillRegion.h]; for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (!pixelIsProtected[i][j]) { for (int k = 0; k < openGrowthPixels.Length; k++) { if (map[i][j] == openGrowthPixels[k]) { open[i - fillRegion.x][j - fillRegion.y] = true; nOpen++; } } } } } // put in the seeds int n = nOpen / seedPointInverseDensity; for (int i = 0; i < n; i++) { int offset = NextRandom(0, nOpen); for (int j = 0; (j < fillRegion.w) && (offset > 0); j++) { for (int k = 0; k < fillRegion.h; k++) { if (open[j][k]) { offset--; if (offset == 0) { map[j + fillRegion.x][k + fillRegion.y] = newGrowthPixel; } } } } } for (int k = 0; k < numberOfGrowPasses; k++) { for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (map[i][j] != newGrowthPixel && open[i - fillRegion.x][j - fillRegion.y]) { int nNeighbors = 0; if (i > 0) { if (j > 0) { if (map[i - 1][j - 1] == newGrowthPixel) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i - 1][j + 1] == newGrowthPixel) { nNeighbors++; } } if (map[i - 1][j] == newGrowthPixel) { nNeighbors++; } } if (i < map.Length - 1) { if (j > 0) { if (map[i + 1][j - 1] == newGrowthPixel) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i + 1][j + 1] == newGrowthPixel) { nNeighbors++; } } if (map[i + 1][j] == newGrowthPixel) { nNeighbors++; } } if (j > 0) { if (map[i][j - 1] == newGrowthPixel) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i][j + 1] == newGrowthPixel) { nNeighbors++; } } int flipChance = nNeighbors * growthPercentPerGrownNeighbor; if (NextRandom(1, 101) < flipChance) { map[i][j] = -1; } } } } for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (map[i][j] == -1 && !pixelIsProtected[i][j]) { map[i][j] = newGrowthPixel; } } } } return new List<MapRoom>(new MapRoom[0]); }
// 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); }
// returns a Path if there is one or null if not public static Path BFSPath(int xStart, int yStart, int xEnd, int yEnd, CanStep stepFrom, CanStep stepTo, StepCost costFrom, DirectedStepCost costTo, MapRectangle limits, bool allowDiagonalSteps) { bool debug = false; if (debug) { Console.WriteLine("BFS start"); } // update bestCost to hold the Dijkstra map if (bestCost == null || bestCost.Length < limits.w) { bestCost = new int[limits.w][]; visitedFrom = new eStep[limits.w][]; } if (bestCost[0] == null || bestCost[0].Length < limits.h) { for (int x = 0; x < limits.w; x++) { bestCost[x] = new int[limits.h]; visitedFrom[x] = new eStep[limits.h]; } } // clear bestCost to -1 = unvisited for (int x = 0; x < limits.w; x++) { for (int y = 0; y < limits.h; y++) { bestCost[x][y] = -1; } } // forward pass List <int> frontX = new List <int>(); List <int> frontY = new List <int>(); List <int> newFrontX = new List <int>(); List <int> newFrontY = new List <int>(); frontX.Add(xStart); frontY.Add(yStart); bestCost[xStart - limits.x][yStart - limits.y] = 0; bool done = false; while (!done) { if (debug) { Console.WriteLine("BFS new iteration, front size = " + frontX.Count); } newFrontX.Clear(); newFrontY.Clear(); done = true; for (int i = 0; i < frontX.Count; i++) { int baseCost = bestCost[frontX[i] - limits.x][ frontY[i] - limits.y]; if (costFrom != null) { baseCost += costFrom(frontX[i], frontY[i]); } if (stepFrom == null || stepFrom(frontX[i], frontY[i])) { for (int j = 0; j < 8; j += (allowDiagonalSteps ? 1 : 2)) { int xNew = frontX[i] + StepDX[j]; int yNew = frontY[i] + StepDY[j]; if (debug) { Console.WriteLine(" attempt step from " + frontX[i] + ", " + frontY[i] + " dir " + j + " delta = " + StepDX[j] + ", " + StepDY[j] + " to " + xNew + ", " + yNew); } if (xNew >= limits.x && yNew >= limits.y && xNew <= limits.x2 && yNew <= limits.y2 && (stepTo == null || stepTo(xNew, yNew))) { int newCost = baseCost; if (costTo != null) { newCost += costTo(xNew, yNew, (eStep)j); } int dx = xNew - limits.x; int dy = yNew - limits.y; int currentCost = bestCost[dx][dy]; if (currentCost == -1 || currentCost > newCost) { bestCost[dx][dy] = newCost; visitedFrom[dx][dy] = ReverseStep[ (int)j]; newFrontX.Add(xNew); newFrontY.Add(yNew); if (debug) { Console.WriteLine(" step to " + xNew + ", " + yNew + " new cost = " + newCost); } done = false; } } } } } if (!done) { List <int> swap = newFrontX; newFrontX = frontX; frontX = swap; swap = newFrontY; newFrontY = frontY; frontY = swap; } } if (bestCost[xEnd - limits.x][yEnd - limits.y] != -1) { // reverse pass and path gen int x = xEnd, y = yEnd; List <eStep> steps = new List <eStep>(); while (x != xStart || y != yStart) { eStep backStep = visitedFrom[x - limits.x][y - limits.y]; steps.Add(backStep); int dx = StepDX[(int)backStep]; int dy = StepDY[(int)backStep]; x += dx; y += dy; } Path solution = new Path(new eStep[steps.Count]); for (int i = 0; i < steps.Count; i++) { solution.Steps[i] = ReverseStep[(int)steps[steps.Count - i - 1]]; } return(solution); } else { return(null); // there is no path } }
// 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; }
private List<MapRoom> BSPBlock(int levelsLeft, int corridorWidth, bool horizontalCut, bool[][] pixelIsProtected, int[][] map, MapRectangle fillRegion) { MapRectangle firstSubregion, secondSubregion; int dx = fillRegion.x; int dy = fillRegion.y; int minimumDim = corridorWidth + 2 * minimumRoomWidth + 4; int lowCutSpot = minimumRoomWidth + 2; if (horizontalCut) { if (fillRegion.h <= minimumDim) { return new List<MapRoom>(new MapRoom[]{new MapRoom(fillRegion)}); } // o r r r x c c x r r r o // ^ int highCutSpot = fillRegion.h - minimumRoomWidth - corridorWidth - 3; int cutSpot = NextRandom(lowCutSpot, highCutSpot + 1); for (int i = 0; i < fillRegion.w; i++) { map[i + dx][cutSpot + dy] = pixelTypes[0]; for (int j = 1; j <= corridorWidth; j++) { map[i + dx][cutSpot + j + dy] = pixelTypes[1]; } map[i + dx][cutSpot + corridorWidth + 1 + dy] = pixelTypes[0]; } firstSubregion = new MapRectangle(fillRegion.x, fillRegion.y, fillRegion.w, cutSpot + 1); secondSubregion = new MapRectangle(fillRegion.x, fillRegion.y + cutSpot + corridorWidth + 1, fillRegion.w, fillRegion.h - cutSpot - corridorWidth - 1); } else { if (fillRegion.w <= minimumDim) { return new List<MapRoom>(new MapRoom[]{new MapRoom(fillRegion)}); } int highCutSpot = fillRegion.w - minimumRoomWidth - corridorWidth - 3; int cutSpot = NextRandom(lowCutSpot, highCutSpot + 1); for (int i = 0; i < fillRegion.h; i++) { map[cutSpot + dx][i + dy] = pixelTypes[0]; for (int j = 1; j <= corridorWidth; j++) { map[cutSpot + j + dx][i + dy] = pixelTypes[1]; } map[cutSpot + corridorWidth + 1 + dx][i + dy] = pixelTypes[0]; } firstSubregion = new MapRectangle(fillRegion.x, fillRegion.y, cutSpot + 1, fillRegion.h); secondSubregion = new MapRectangle(fillRegion.x + cutSpot + corridorWidth + 1, fillRegion.y, fillRegion.w - cutSpot - corridorWidth - 1, fillRegion.h); } if (levelsLeft >= 1) { // split me int newCorridorWidth = corridorWidth - 1; if (newCorridorWidth <= 1) { newCorridorWidth = 1; } List<MapRoom> list1 = BSPBlock(levelsLeft - 1, newCorridorWidth, !horizontalCut, pixelIsProtected, map, firstSubregion); List<MapRoom> list2 = BSPBlock(levelsLeft - 1, newCorridorWidth, !horizontalCut, pixelIsProtected, map, secondSubregion); list1.AddRange(list2); return list1; } else { return new List<MapRoom>(new MapRoom[]{new MapRoom(firstSubregion), new MapRoom(secondSubregion)}); } }
public override List<MapRoom> Run(int[][] map, MapRectangle fillRegion, List<MapRoom> roomsToInclude) { bool[][] pixelIsProtected = BuildProtectedMap(roomsToInclude, map.Length, map[0].Length); // clear to solid for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (!pixelIsProtected[i][j]) { map[i][j] = pixelTypes[0]; } } } // put in the horizontal seed corridors int n = fillRegion.h / seedCorridorAverageSpacing; for (int i = 0; i < n; i++) { int l = NextRandom(seedCorridorAverageLength / 2, 3 * seedCorridorAverageLength / 2 + 1); int offset = 0; if (l >= fillRegion.w) { l = fillRegion.w; } else { offset = NextRandom(0, fillRegion.w - l + 1); } int crossOffset = NextRandom(fillRegion.y, fillRegion.y2 + 1); for (int j = offset; j < offset + l; j++) { if (!pixelIsProtected[j + fillRegion.x][crossOffset]) { map[j + fillRegion.x][crossOffset] = pixelTypes[1]; } } } // put in the vertical seed corridors n = fillRegion.w / seedCorridorAverageSpacing; for (int i = 0; i < n; i++) { int l = NextRandom(seedCorridorAverageLength / 2, 3 * seedCorridorAverageLength / 2 + 1); int offset = 0; if (l >= fillRegion.h) { l = fillRegion.h; } else { offset = NextRandom(0, fillRegion.h - l + 1); } int crossOffset = NextRandom(fillRegion.x, fillRegion.x2 + 1); for (int j = offset; j < offset + l; j++) { if (!pixelIsProtected[crossOffset][j + fillRegion.y]) { map[crossOffset][j + fillRegion.y] = pixelTypes[1]; } } } for (int k = 0; k < numberOfDecays; k++) { for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (map[i][j] == pixelTypes[0] && !pixelIsProtected[i][j]) { int nNeighbors = 0; if (i > 0) { if (j > 0) { if (map[i - 1][j - 1] == pixelTypes[1]) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i - 1][j + 1] == pixelTypes[1]) { nNeighbors++; } } if (map[i - 1][j] == pixelTypes[1]) { nNeighbors++; } } if (i < map.Length - 1) { if (j > 0) { if (map[i + 1][j - 1] == pixelTypes[1]) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i + 1][j + 1] == pixelTypes[1]) { nNeighbors++; } } if (map[i + 1][j] == pixelTypes[1]) { nNeighbors++; } } if (j > 0) { if (map[i][j - 1] == pixelTypes[1]) { nNeighbors++; } } if (j < map[i].Length - 1) { if (map[i][j + 1] == pixelTypes[1]) { nNeighbors++; } } int flipChance = nNeighbors * decayPercentPerDecayedNeighbor; if (NextRandom(1, 101) < flipChance) { map[i][j] = -1; } } } } for (int i = fillRegion.x; i <= fillRegion.x2; i++) { for (int j = fillRegion.y; j <= fillRegion.y2; j++) { if (map[i][j] == -1 && !pixelIsProtected[i][j]) { map[i][j] = pixelTypes[1]; } } } } return new List<MapRoom>(new MapRoom[0]); }
public static void CalculateBresenhamProductsToRectangle(int fromX, int fromY, int[][] map, MapRectangle rectangle, UpdateProductForSquare update, int startingProduct, bool includeFirstSquare, bool includeLastSquare, int[][] outputMap) { // top and bottom edges for (int x = rectangle.x; x <= rectangle.x2; x++) { outputMap[fromX][fromY] = startingProduct; CalculateBresenhamProductSquareToSquare(fromX, fromY, x, rectangle.y, map, (previous, mapval, xs, ys) => { outputMap[xs][ys] = update(previous, mapval); return outputMap[xs][ys]; }, startingProduct, includeFirstSquare, includeLastSquare); outputMap[fromX][fromY] = startingProduct; CalculateBresenhamProductSquareToSquare(fromX, fromY, x, rectangle.y2, map, (previous, mapval, xs, ys) => { outputMap[xs][ys] = update(previous, mapval); return outputMap[xs][ys]; }, startingProduct, includeFirstSquare, includeLastSquare); } // right and left edges for (int y = rectangle.y + 1; y <= rectangle.y2 - 1; y++) { outputMap[fromX][fromY] = startingProduct; CalculateBresenhamProductSquareToSquare(fromX, fromY, rectangle.x, y, map, (previous, mapval, xs, ys) => { outputMap[xs][ys] = update(previous, mapval); return outputMap[xs][ys]; }, startingProduct, includeFirstSquare, includeLastSquare); outputMap[fromX][fromY] = startingProduct; CalculateBresenhamProductSquareToSquare(fromX, fromY, rectangle.x2, y, map, (previous, mapval, xs, ys) => { outputMap[xs][ys] = update(previous, mapval); return outputMap[xs][ys]; }, startingProduct, includeFirstSquare, includeLastSquare); } }
static public void Main() { //UI d = new VT100UI(); VT100UI d = new VT100UI(); // This is just a placeholder for (int x = 0; x < 80; x++) { d.DrawAt(x, 3, " ", 0, 0, 0, 0, 0, 64); } for (int x = 0; x < 80; x++) { d.DrawAt(x, 22, " ", 0, 0, 0, 0, 0, 64); } UIMapElement map_element = d.MapElement( x: 0, y: 4, h: 17 ); ClearMapGenerator gen = new ClearMapGenerator(new int[] { 0, 0 }, MapCoordinate.GenerateRandom()); map_element.map = new MapData(80, 40); ClearMapGenerator gen2 = new ClearMapGenerator(new int[] { 2, 1 }, MapCoordinate.GenerateRandom()); gen2.Run(map_element.map.grid, new MapRectangle(10, 10, 10, 10), null); List <MapRoom> blockedList = new List <MapRoom>(); MapRectangle fullArea = new MapRectangle(0, 0, 80, 40); blockedList.Add(new MapRoom(new MapRectangle(10, 10, 10, 10))); gen.Run(map_element.map.grid, fullArea, blockedList); DungeonRoomMapGenerator drmg = new DungeonRoomMapGenerator(new int[] { 5, 6, 7 }, MapCoordinate.GenerateRandom(), 5, 12, 10, 3); List <MapRoom> allRooms = drmg.Run(map_element.map.grid, fullArea, blockedList); DungeonCorridorMapGenerator dcmg = new DungeonCorridorMapGenerator( new int[] { 5, 6, 7 }, MapCoordinate.GenerateRandom(), 2, new int[] { 0, 100000, 100000, 0, 0, 100000, 0, 0 }); dcmg.Run(map_element.map.grid, fullArea, allRooms); map_element.map.AddSpaceType(glyph: '#', r: 128, g: 128, b: 128); map_element.map.AddSpaceType(glyph: '#', r: 128, g: 128, b: 128); map_element.map.AddSpaceType(glyph: '#', r: 128, g: 128, b: 128); map_element.map.AddSpaceType(glyph: '*'); map_element.map.AddSpaceType(glyph: '~', r: 0, g: 32, b: 255); map_element.map.AddSpaceType(glyph: '#', r: 128, g: 128, b: 128); map_element.map.AddSpaceType(glyph: '.', r: 64, g: 64, b: 64); map_element.map.AddSpaceType(glyph: '+', r: 128, g: 64, b: 0); d.DrawAt(54, 3, " 5 targets in range ", 255, 255, 192, 0, 0, 0); d.DrawAt(74, 3, "[T] ", 192, 192, 255, 0, 0, 0); d.DrawAt(58, 22, " Press for help ", 255, 255, 192, 0, 0, 0); d.DrawAt(65, 22, "[?]", 192, 192, 255, 0, 0, 0); map_element.Draw(); d.DrawScreen(); }
private List <MapRoom> BSPBlock(int levelsLeft, int corridorWidth, bool horizontalCut, bool[][] pixelIsProtected, int[][] map, MapRectangle fillRegion) { MapRectangle firstSubregion, secondSubregion; int dx = fillRegion.x; int dy = fillRegion.y; int minimumDim = corridorWidth + 2 * minimumRoomWidth + 4; int lowCutSpot = minimumRoomWidth + 2; if (horizontalCut) { if (fillRegion.h <= minimumDim) { return(new List <MapRoom>(new MapRoom[] { new MapRoom(fillRegion) })); } // o r r r x c c x r r r o // ^ int highCutSpot = fillRegion.h - minimumRoomWidth - corridorWidth - 3; int cutSpot = NextRandom(lowCutSpot, highCutSpot + 1); for (int i = 0; i < fillRegion.w; i++) { map[i + dx][cutSpot + dy] = pixelTypes[0]; for (int j = 1; j <= corridorWidth; j++) { map[i + dx][cutSpot + j + dy] = pixelTypes[1]; } map[i + dx][cutSpot + corridorWidth + 1 + dy] = pixelTypes[0]; } firstSubregion = new MapRectangle(fillRegion.x, fillRegion.y, fillRegion.w, cutSpot + 1); secondSubregion = new MapRectangle(fillRegion.x, fillRegion.y + cutSpot + corridorWidth + 1, fillRegion.w, fillRegion.h - cutSpot - corridorWidth - 1); } else { if (fillRegion.w <= minimumDim) { return(new List <MapRoom>(new MapRoom[] { new MapRoom(fillRegion) })); } int highCutSpot = fillRegion.w - minimumRoomWidth - corridorWidth - 3; int cutSpot = NextRandom(lowCutSpot, highCutSpot + 1); for (int i = 0; i < fillRegion.h; i++) { map[cutSpot + dx][i + dy] = pixelTypes[0]; for (int j = 1; j <= corridorWidth; j++) { map[cutSpot + j + dx][i + dy] = pixelTypes[1]; } map[cutSpot + corridorWidth + 1 + dx][i + dy] = pixelTypes[0]; } firstSubregion = new MapRectangle(fillRegion.x, fillRegion.y, cutSpot + 1, fillRegion.h); secondSubregion = new MapRectangle(fillRegion.x + cutSpot + corridorWidth + 1, fillRegion.y, fillRegion.w - cutSpot - corridorWidth - 1, fillRegion.h); } if (levelsLeft >= 1) { // split me int newCorridorWidth = corridorWidth - 1; if (newCorridorWidth <= 1) { newCorridorWidth = 1; } List <MapRoom> list1 = BSPBlock(levelsLeft - 1, newCorridorWidth, !horizontalCut, pixelIsProtected, map, firstSubregion); List <MapRoom> list2 = BSPBlock(levelsLeft - 1, newCorridorWidth, !horizontalCut, pixelIsProtected, map, secondSubregion); list1.AddRange(list2); return(list1); } else { return(new List <MapRoom>(new MapRoom[] { new MapRoom(firstSubregion), new MapRoom(secondSubregion) })); } }