public FilledRegion Apply(FillData data) { List <Region> spawnAreas = new List <Region>(); //Get data. Generation.BeingFilled = data.BeingFilled; int numb = Generation.NumbPlateaus; int width = Generation.PlateauWidth; int space = Generation.SpaceBetweenPlateaus; int border = Generation.Border; //Plateau location data. int height = (int)Math.Round((PlateauRelativeHeight * data.BeingFilled.Height), 0); if (height >= data.BeingFilled.Height) { height = data.BeingFilled.Height - 1; } int top = data.BeingFilled.Bottom - height; //Add the plateaus. Region r; for (int i = 0; i < numb; ++i) { r = new Region(data.BeingFilled.Left + border + (i * (space + width)), top, width - 1, data.BeingFilled.Bottom - top); data.FillRegion(true, r); spawnAreas.Add(new Region(new Location(r.Left, data.BeingFilled.Top), r.TopRight.Above)); } //Make room for any holes that the plateaus covered. foreach (Location l in data.HolesAlongPerimeter()) { //The hole is covered if it is just under the region and the space right above it is covered. if (data.BeingFilled.Touches(l.Above, true, true, false) && data.GetMapAt(l.Above)) { //Make a litle tunnel under the plateau. int[] plateauSides = PlateauSides(l.X, numb, width, space, border, data.BeingFilled.Left, data.BeingFilled.Right); Region cleared = new Region(plateauSides[0], data.BeingFilled.Bottom, width - 1, 0); data.FillRegion(false, cleared); } } return(new SteppedHallwayRegion(data.BeingFilled, spawnAreas)); }
public FilledRegion Apply(FillData data) { //Keep track of the spawn areas above the steps, indexed by y coordinate. Dictionary <int, Region> platformSpaces = new Dictionary <int, Region>(); //Get step data. int stepWidth = (int)Math.Round(StepSizeScale * (data.BeingFilled.Width + 1), 0); int spaceWidth = data.BeingFilled.Width + 1 - stepWidth - stepWidth; bool left = true; Location line1, line2; for (int y = data.BeingFilled.Bottom - 1; y > data.BeingFilled.Top; y -= Space) { //Fill the line. if (left) { line1 = new Location(data.BeingFilled.Left, y); line2 = new Location(data.BeingFilled.Left + stepWidth - 1, y); data.FillLine(true, line1, line2); platformSpaces.Add(y, new Region(line1, line2, true)); } else { line1 = new Location(data.BeingFilled.Left + stepWidth + spaceWidth, y); line2 = new Location(data.BeingFilled.Right, y); data.FillLine(true, line1, line2); platformSpaces.Add(y, new Region(line1, line2, true)); } //Change sides. left = !left; } //Free any holes. foreach (Location l in data.HolesAlongPerimeter()) { //If the hole is on the left side and there's a platform in the way: if (data.BeingFilled.Touches(l.Right, true, true, false) && data.GetMapAt(l.Right)) { //Remove the left edge of the platform. data.SetMapAt(l.Right, false); Region r = platformSpaces[l.Y]; ++r.X; --r.Width; platformSpaces[l.Y] = r; } //Otherwise, if the hole is on the right side and there's a platform in the way: else if (data.BeingFilled.Touches(l.Left, true, true, false) && data.GetMapAt(l.Left)) { //Remove the right edge of the platform. data.SetMapAt(l.Left, false); Region r = platformSpaces[l.Y]; --r.Width; platformSpaces[l.Y] = r; } } return(new AlternatingStepsRegion(data.BeingFilled, platformSpaces.Values)); }
public void IterateFillPattern() { //Already done? if (iterateFillPatternsRegionCount >= Regions.Count) { return; } //Run an iteration. FilledRegion temp; Region r = Regions[iterateFillPatternsRegionCount]; iterateFillPatternsRegionCount++; //Pick a random applicable pattern (assuming one exists) and apply it. FillPattern p = Settings.MostSuitable(r); if (p != null) { //Clear the space, and apply the pattern. FillData.BeingFilled = r; FillData.FillRegion(false, r); temp = p.Apply(FillData); //If the filled region is blank, replace it with a BlankRegion. bool blank = true; for (int i = temp.Covering.Left; i <= temp.Covering.Right; ++i) { for (int j = temp.Covering.Top; j <= temp.Covering.Bottom; ++j) { if (FillData.GetMapAt(new Location(i, j))) { blank = false; break; } } if (!blank) { break; } } if (blank) { temp = new BlankRegion(temp.Covering); } //Now add it. FilledRegions.Add(temp); Region r2; //Make sure the spawn points are all valid. foreach (Spawns s in FilledRegions[FilledRegions.Count - 1].PotentialSpawns.Keys) { for (int i = 0; i < FilledRegions[FilledRegions.Count - 1].PotentialSpawns[s].Count; ++i) { r2 = FilledRegions[FilledRegions.Count - 1].PotentialSpawns[s][i]; if (r2.Width < 0 || r2.Height < 0) { FilledRegions[FilledRegions.Count - 1].PotentialSpawns[s].RemoveAt(i--); } } } } //If no regions fit, add a "NoRegion". else { FilledRegions.Add(new NoRegion(r)); } }
/// <summary> /// Gets all continuous left/right Lines from the given level using all the walls in the given column. /// The Lines are indexed by all wall bounds that make up part of that indexed Line. /// </summary> public static void GetVerticalLines(FillData data, WallToLines associations, int col) { int startingY, currentY; Interval temp; ColType current; bool rightCol = (col == data.Map.GetLength(0) - 1); //Do the algorithm for both the left and the right of the column. int currentCol; for (int dir = -1; dir < 2; dir += 2) { currentCol = col + dir; current = (currentCol > col ? ColType.Right : ColType.Left); //Take care of the edge case where the whole row is a valid line. bool colFree = true; for (int j = 0; j < data.Map.GetLength(1); ++j) { if (data.GetMapAt(new Location(currentCol, j)) || !data.GetMapAt(new Location(col, j))) { colFree = false; break; } } //If the whole column is one line, just use that. if (colFree) { //If the level wraps around, use a large line. if (data.WrapY) { associations.AddReferences(GetBounds(new Line(Orientation.Vertical, new Interval(0, data.Map.GetLength(1) - 1, true, 2), col)), current, new Line(Orientation.Vertical, new Interval(-data.Map.GetLength(1), 2.0f * data.Map.GetLength(1), true, 2), (col + currentCol) * 0.5f)); } else { associations.AddReferences(GetBounds(new Line(Orientation.Vertical, new Interval(0, data.Map.GetLength(1) - 1, true, 2), col)), current, new Line(Orientation.Vertical, new Interval(0, data.Map.GetLength(1) - 1, true, 2), col)); } } //Otherwise, go through one wall at a time and build individual collections of Lines. else { //An edge is a whole Line if it spans an unbroken column of walls with no walls covering the edge. //Use a counter to run through the whole column in groups of unbroken walls. startingY = 0; currentY = 0; temp = null; while (startingY < data.Map.GetLength(1)) { //Get the next valid spot to start from. while ((!data.GetMapAt(new Location(col, startingY)) || data.GetMapAt(new Location(currentCol, startingY))) && startingY < data.Map.GetLength(1)) { currentY += 1; startingY = currentY; } if (startingY >= data.Map.GetLength(1)) { break; } //Keep the counter going as long as the next spot is valid (i.e. // there is a wall to the side but not in the way). while (data.GetMapAt(new Location(col, currentY + 1)) && !data.GetMapAt(new Location(currentCol, currentY + 1)) && currentY < data.Map.GetLength(1)) { currentY += 1; } //Now make the line. temp = new Interval(startingY, currentY, true, 2); associations.AddReferences(GetBounds(new Line(Orientation.Vertical, temp, col)), current, new Line(Orientation.Vertical, temp, (col + currentCol) * 0.5f)); //If this is near the top, wrap it around to the bottom. if (data.WrapY && temp.Start < 2.0f) { associations.AddReferences(GetBounds(new Line(Orientation.Vertical, temp + data.WorldSize.Y, col)), current, new Line(Orientation.Vertical, temp + data.WorldSize.Y, (col + currentCol) * 0.5f)); } //Move to the next spot in the column. startingY = currentY + 1; currentY = startingY; } //If the level wraps around in the Y, take the last Line and wrap it around. if (temp != null && data.WrapY) { associations.AddReferences(GetBounds(new Line(Orientation.Vertical, temp - data.WorldSize.Y, col)), current, new Line(Orientation.Vertical, temp - data.WorldSize.Y, (col + currentCol) * 0.5f)); } } } }
/// <summary> /// Gets all continuous top/bottom Lines from the given level using all the walls in the given row. /// The Lines are indexed by all wall bounds that make up part of that indexed Line. /// </summary> public static void GetHorizontalLines(FillData data, WallToLines associations, int row) { int startingX, currentX; Interval temp; ColType current; bool bottomRow = (row == data.Map.GetLength(1) - 1); //Do the algorithm for both above and below the row. int currentRow; for (int dir = -1; dir < 2; dir += 2) { currentRow = row + dir; current = (currentRow < row ? ColType.Bottom : ColType.Top); //There is one special case: the whole row is a valid line. bool rowFree = true; for (int i = 0; i < data.Map.GetLength(0); ++i) { if (data.GetMapAt(new Location(i, currentRow)) || !data.GetMapAt(new Location(i, row))) { rowFree = false; break; } } //If the whole row is one line, just use that. if (rowFree) { //If the level wraps around, use a large line. if (data.WrapX) { associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, new Interval(0, data.Map.GetLength(0) - 1, true, 2), row)), current, new Line(Orientation.Horizontal, new Interval(-data.Map.GetLength(0), 2.0f * data.Map.GetLength(0), true, 2), (row + currentRow) * 0.5f)); } else { associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, new Interval(0, data.Map.GetLength(0) - 1, true, 2), row)), current, new Line(Orientation.Horizontal, new Interval(0, data.Map.GetLength(0) - 1, true, 2), row)); } } //Otherwise, go through one wall at a time and build individual collections of Lines. else { //An edge is a whole Line if it spans an unbroken row of walls with no walls covering the edge. //Use a counter to run through the whole row in groups of unbroken rows. startingX = 0; currentX = 0; temp = null; while (startingX < data.Map.GetLength(0)) { //Get the next valid spot to start from. while ((!data.GetMapAt(new Location(startingX, row)) || data.GetMapAt(new Location(startingX, currentRow))) && startingX < data.Map.GetLength(0)) { currentX += 1; startingX = currentX; } if (startingX >= data.Map.GetLength(0)) { break; } //Keep the counter going as long as the next spot is valid (i.e. // there is a wall in this row but not above/underneath). while (data.GetMapAt(new Location(currentX + 1, row)) && !data.GetMapAt(new Location(currentX + 1, currentRow)) && currentX < data.Map.GetLength(0)) { currentX += 1; } //Now make the line. temp = new Interval(startingX, currentX, true, 2); associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, temp, row)), current, new Line(Orientation.Horizontal, temp, (row + currentRow) * 0.5f)); //If this is near the left, wrap it around to the right. if (data.WrapX && temp.Start < 2.0f) { associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, temp + data.WorldSize.X, row)), current, new Line(Orientation.Horizontal, temp + data.WorldSize.X, (row + currentRow) * 0.5f)); } //Move to the next spot in the row. startingX = currentX + 1; currentX = startingX; } //If the level wraps around in the X, take the last Line and wrap it around. if (temp != null && data.WrapX) { associations.AddReferences(GetBounds(new Line(Orientation.Horizontal, temp - data.WorldSize.X, row)), current, new Line(Orientation.Horizontal, temp - data.WorldSize.X, (row + currentRow) * 0.5f)); } } } }
public FilledRegion Apply(FillData data) { //The spawning areas. List <Region> spawningAreas = new List <Region>(); //Get/set some data. Region area = data.BeingFilled; PlateauGeneration.BeingFilled = data.BeingFilled; //If the corridor is going to be vertical, flip the width and height. if (area.Height > area.Width) { PlateauGeneration.BeingFilled = new Region(area.Y, area.X, area.Height, area.Width); } int numb = PlateauGeneration.NumbPlateaus; int plateauSize = PlateauGeneration.PlateauWidth; int space = PlateauGeneration.SpaceBetweenPlateaus; int border = PlateauGeneration.Border; //Plateau size data. //"maxSize" is the largest allowable hurdle height. int maxSize = PlateauGeneration.BeingFilled.Height - 1; if (area.Height > area.Width) { //Vertical. //Add the plateaus. int hurdleWidth, plateauExtent; for (int i = 0; i < numb; ++i) { //Get a width within the given random variation. hurdleWidth = (int)Math.Round((area.Width + 1) * (HurdleAverageSpaceScale + ((2 * HurdleHeightVariance * (float)GeneratorSettings.R.NextDouble()) - HurdleHeightVariance)), 0); //Keep it constrained. if (hurdleWidth > maxSize) { hurdleWidth = maxSize; } if (hurdleWidth < 1) { hurdleWidth = 1; } //Get the width of the plateau given the size of a hurdle. plateauExtent = area.Width + 1 - hurdleWidth; plateauExtent /= 2; //Fill in the plateaus. data.FillRegion(true, new Region(area.Left, area.Top + border + (i * (space + plateauSize)), plateauExtent - 1, plateauSize - 1)); if ((2 * plateauExtent) + hurdleWidth >= area.Width + 1) { data.FillRegion(true, new Region(area.Right - plateauExtent + 1, area.Top + border + (i * (space + plateauSize)), plateauExtent - 1, plateauSize - 1)); } else { data.FillRegion(true, new Region(area.Right - plateauExtent, area.Top + border + (i * (space + plateauSize)), plateauExtent, plateauSize - 1)); } } //Make room for any holes that the plateaus covered. foreach (Location l in data.HolesAlongPerimeter()) { //The hole is covered if it is just left/right of the region and the space just right/left of it (respectively) is filled. if ((area.Touches(l.Left, true, true, false) && data.GetMapAt(l.Left)) || (area.Touches(l.Right, true, true, false) && data.GetMapAt(l.Right))) { //Make a little tunnel under the plateau. int[] plateauSides = SteppedHallwayPattern.PlateauSides(l.Y, numb, plateauSize, space, border, area.Top, area.Bottom); Region cleared; if (l.X - 1 == area.Right) { cleared = new Region(data.BeingFilled.Right, plateauSides[0], 0, plateauSize - 1); } else { cleared = new Region(data.BeingFilled.Left, plateauSides[0], 0, plateauSize - 1); } data.FillRegion(false, cleared); } } } else { //Horizontal. //Add the plateaus. int hurdleHeight, plateauHeight; for (int i = 0; i < numb; ++i) { //Get a height within the given random variation. hurdleHeight = (int)Math.Round((area.Height + 1) * (HurdleAverageSpaceScale + ((2 * HurdleHeightVariance * (float)GeneratorSettings.R.NextDouble()) - HurdleHeightVariance)), 0); //Keep it constrained. if (hurdleHeight > maxSize) { hurdleHeight = maxSize; } if (hurdleHeight < 1) { hurdleHeight = 1; } //Get the height of the plateau given the size of a hurdle. plateauHeight = area.Height + 1 - hurdleHeight; plateauHeight /= 2; //Fill in the plateaus. data.FillRegion(true, new Region(area.Left + border + (i * (space + plateauSize)), area.Top, plateauSize - 1, plateauHeight - 1)); if ((2 * plateauHeight) + hurdleHeight >= area.Height + 1) { data.FillRegion(true, new Region(area.Left + border + (i * (space + plateauSize)), area.Bottom - plateauHeight + 1, plateauSize - 1, plateauHeight - 1)); spawningAreas.Add(new Region(area.Left + border + (i * (space + plateauSize)), area.Top + plateauHeight, plateauSize - 1, data.BeingFilled.Height - plateauHeight - plateauHeight - 2)); } else { data.FillRegion(true, new Region(area.Left + border + (i * (space + plateauSize)), area.Bottom - plateauHeight, plateauSize - 1, plateauHeight)); spawningAreas.Add(new Region(area.Left + border + (i * (space + plateauSize)), area.Top + plateauHeight, plateauSize - 1, data.BeingFilled.Height - plateauHeight - plateauHeight - 1)); } } } //Make room for any holes that the plateaus covered. foreach (Location l in data.HolesAlongPerimeter()) { //Horizontal. if (area.Height < area.Width) { //The hole is covered if it is just below/above the region and the space above/below it (respectively) is filled. if ((area.Touches(l.Above, true, true, false) && data.GetMapAt(l.Above)) || (area.Touches(l.Below, true, true, false) && data.GetMapAt(l.Below))) { //Make a little tunnel under the plateau. int[] plateauSides = SteppedHallwayPattern.PlateauSides(l.X, numb, plateauSize, space, border, area.Left, area.Right); Region cleared; if (l.Y - 1 == area.Bottom) { cleared = new Region(plateauSides[0], data.BeingFilled.Bottom, plateauSize - 1, 0); } else { cleared = new Region(plateauSides[0], data.BeingFilled.Top, plateauSize - 1, 0); } data.FillRegion(false, cleared); } } //Vertical. else if ((area.Touches(l.Left, true, true, false) && data.GetMapAt(l.Left)) || (area.Touches(l.Right, true, true, false) && data.GetMapAt(l.Right))) { //Make a little tunnel under the plateau. int[] plateauSides = SteppedHallwayPattern.PlateauSides(l.Y, numb, plateauSize, space, border, area.Top, area.Bottom); Region cleared; if (l.X - 1 == area.Right) { cleared = new Region(data.BeingFilled.Right, plateauSides[0], 0, plateauSize - 1); } else { cleared = new Region(data.BeingFilled.Left, plateauSides[0], 0, plateauSize - 1); } data.FillRegion(false, cleared); } } //Return the new regions. return(new ThickHurdleRegion(data.BeingFilled, spawningAreas)); }
public FilledRegion Apply(FillData data) { //Start on either the relative top or bottom of the corridor. bool top = MathF.R.NextDouble() > 0.5; //Set up the plateau properties. bool horizontal = data.BeingFilled.Width > data.BeingFilled.Height; if (horizontal) { Generation.BeingFilled = data.BeingFilled; } else { Generation.BeingFilled = new Region(data.BeingFilled.Y, data.BeingFilled.X, data.BeingFilled.Height, data.BeingFilled.Width); } int spaceBetween = Generation.SpaceBetweenPlateaus; int border = Generation.Border; int plateauWidth = Generation.PlateauWidth; int numbPlateaus = Generation.NumbPlateaus; //Fill the area. Also keep track of the free space above/below plateaus. List <Region> freeAreas = new List <Region>(); for (int i = 0; i < numbPlateaus; ++i) { if (top) { if (horizontal) { data.FillRegion(true, new Region(data.BeingFilled.Left + border + (i * (spaceBetween + plateauWidth)), data.BeingFilled.Top, plateauWidth - 1, data.BeingFilled.Height - 1)); freeAreas.Add(new Region(data.BeingFilled.Left + border + (i * (spaceBetween + plateauWidth)), data.BeingFilled.Bottom, plateauWidth - 1, 0)); } else { data.FillRegion(true, new Region(data.BeingFilled.Left, data.BeingFilled.Top + border + (i * (spaceBetween + plateauWidth)), data.BeingFilled.Width - 1, plateauWidth - 1)); freeAreas.Add(new Region(data.BeingFilled.Left + 1, data.BeingFilled.Top + border + (i * (spaceBetween + plateauWidth)) - 1, data.BeingFilled.Width - 2, 0)); } } else { if (horizontal) { data.FillRegion(true, new Region(data.BeingFilled.Left + border + (i * (spaceBetween + plateauWidth)), data.BeingFilled.Top + 1, plateauWidth - 1, data.BeingFilled.Height - 1)); freeAreas.Add(new Region(data.BeingFilled.Left + border + (i * (spaceBetween + plateauWidth)), data.BeingFilled.Top, plateauWidth - 1, 0)); } else { data.FillRegion(true, new Region(data.BeingFilled.Left + 1, data.BeingFilled.Top + border + (i * (spaceBetween + plateauWidth)), data.BeingFilled.Width - 1, plateauWidth - 1)); freeAreas.Add(new Region(data.BeingFilled.Left + 1, data.BeingFilled.Top + border + (i * (spaceBetween + plateauWidth)) - 1, data.BeingFilled.Width - 2, 0)); } } top = !top; } Region area = data.BeingFilled; //Make room for any holes that the plateaus covered. //TODO: Instead of clearing out the bottom, just clear that column of plateau. Possibly also do this for other plateau patterns? foreach (Location l in data.HolesAlongPerimeter()) { //Horizontal. if (area.Height < area.Width) { //The hole is covered if it is just below/above the region and the space above/below it (respectively) is filled. if ((area.Touches(l.Above, true, true, false) && data.GetMapAt(l.Above)) || (area.Touches(l.Below, true, true, false) && data.GetMapAt(l.Below))) { //Make a little tunnel under the plateau. int[] plateauSides = SteppedHallwayPattern.PlateauSides(l.X, numbPlateaus, plateauWidth, spaceBetween, border, area.Left, area.Right); Region cleared; if (l.Y - 1 == area.Bottom) { cleared = new Region(plateauSides[0], data.BeingFilled.Bottom, plateauWidth - 1, 0); } else { cleared = new Region(plateauSides[0], data.BeingFilled.Top, plateauWidth - 1, 0); } data.FillRegion(false, cleared); } } //Vertical else if ((area.Touches(l.Left, true, true, false) && data.GetMapAt(l.Left)) || (area.Touches(l.Right, true, true, false) && data.GetMapAt(l.Right))) { //Make a little tunnel under the plateau. int[] plateauSides = SteppedHallwayPattern.PlateauSides(l.Y, numbPlateaus, plateauWidth, spaceBetween, border, area.Top, area.Bottom); Region cleared; if (l.X - 1 == area.Right) { cleared = new Region(data.BeingFilled.Right, plateauSides[0], 0, plateauWidth - 1); } else { cleared = new Region(data.BeingFilled.Left, plateauSides[0], 0, plateauWidth - 1); } data.FillRegion(false, cleared); } } if (horizontal) { return(new ZipperRegion(data.BeingFilled, freeAreas)); } else { return(new ZipperRegion(data.BeingFilled, new List <Region>())); } }