public FilledRegion Apply(FillData data) { //Keep track of the platforms as individual spawning regions. List <Region> playSpawns = new List <Region>(); int startingX; //Use a counter. for (int y = data.BeingFilled.Bottom - SpaceBetween; y >= data.BeingFilled.Top + SpaceBetween; y -= SpaceBetween) { startingX = data.BeingFilled.Left + Border; //Go through each block in the current line. int x; for (x = data.BeingFilled.Left + Border; x <= data.BeingFilled.Right - Border; ++x) { //With a certain chance, fill it. if (MathF.R.NextDouble() > PercentageHoles) { data.SetMapAt(new Location(x, y), true); } //Otherwise, cut off the platform region here. else { playSpawns.Add(new Region(new Location(startingX, y - 1), new Location(x - 1, y - 1))); startingX = x + 1; } } playSpawns.Add(new Region(new Location(startingX, y - 1), new Location(x - 1, y - 1))); } return(new PlatformsRegion(data.BeingFilled, playSpawns)); }
public FilledRegion Apply(FillData data) { //Get the space between each shell. In most cases it should be 1. //In the case of a very large room, it could be 2. //Played around with a graphing calculator to get a good function that reflects this. int minSpace = 1, maxSpace = 2; double coefficient = Math.Sqrt(maxSpace - minSpace) / (data.BeingFilled.Area - MinArea); int spaceBetweenShells = (int)Math.Round(Math.Pow(coefficient * (data.BeingFilled.Area - MinArea), 2.0) + 1.0, 0); //Make sure my function is valid. if (spaceBetweenShells < 1 || spaceBetweenShells > 2) { throw new InvalidOperationException("Oops!"); } //Continuously fill in smaller and smaller shells centered around the region center. Region shell = new Region(data.BeingFilled.TopLeft.Right.Below, data.BeingFilled.BottomRight.Left.Above, true); sbyte holeDir = 1; //Smallest-allowable shell is 3x3, which means a region of width/height 2. while (shell.Area > 4) { //Fill in the perimeter. data.FillPerimeter(true, shell); //Clear the hole. if (holeDir < 0) { data.SetMapAt(shell.LeftMid, false); } else { data.SetMapAt(shell.RightMid, false); } //Flip the side the next hole will be on. holeDir *= -1; //Shrink the shell. for (int i = 0; i < spaceBetweenShells; ++i) { shell = new Region(shell.TopLeft.Right.Below, shell.BottomRight.Left.Above, false); } } return(new ConcentricSquaresRegion(data.BeingFilled, new Region(shell.TopLeft.Left.Above, shell.BottomRight.Right.Below))); }
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 FilledRegion Apply(FillData data) { Region clearArea = new Region(data.BeingFilled.Center.Left.Above, data.BeingFilled.Center.Right.Below); //Fill the inner ring. //Move from each corner of the X to the center. Location counter; Location center = data.BeingFilled.Center; bool moveHorizontally; bool horizontalBias = data.BeingFilled.Width > data.BeingFilled.Height; //Fill in the center. data.FillRegion(true, new Region(clearArea.TopLeft.Above.Left, clearArea.BottomRight.Below.Right)); for (int i = 0; i < 4; ++i) { //Get the point to start from. switch (i) { case 0: counter = data.BeingFilled.TopLeft.Right.Below; data.SetMapAt(counter, false); break; case 1: counter = data.BeingFilled.TopRight.Left.Below; data.SetMapAt(counter, false); break; case 2: counter = data.BeingFilled.BottomLeft.Right.Above; data.SetMapAt(counter, false); break; case 3: counter = data.BeingFilled.BottomRight.Left.Above; data.SetMapAt(counter, false); break; default: throw new InvalidOperationException(); } //Clear a path to the center. while (!clearArea.Touches(counter, true, true, true)) { //Get which direction to move in. float relativeDistX = Math.Abs(counter.X - center.X) / (float)data.BeingFilled.Width; float relativeDistY = Math.Abs(counter.Y - center.Y) / (float)data.BeingFilled.Height; if (relativeDistX > relativeDistY) { moveHorizontally = true; } else if (relativeDistX < relativeDistY) { moveHorizontally = false; } else { moveHorizontally = horizontalBias; } //Move that direction, add the region, and fill part of the X after moving. if (moveHorizontally) { int amount = Math.Sign(center.X - counter.X); counter.X += amount; data.SetMapAt(counter, false); data.SetMapAt(new Location(counter.X + amount, counter.Y), true); if (counter.Y > 1 && counter.Y < data.BeingFilled.Bottom - 1) { data.SetMapAt(new Location(counter.X, counter.Y + Math.Sign(counter.Y - center.Y)), true); } } else { int amount = Math.Sign(center.Y - counter.Y); counter.Y += amount; data.SetMapAt(counter, false); data.SetMapAt(new Location(counter.X, counter.Y + amount), true); if (counter.X > 1 && counter.X < data.BeingFilled.Right - 1) { data.SetMapAt(new Location(counter.X + Math.Sign(counter.X - center.X), counter.Y), true); } } } //Keep the center clear. data.FillRegion(false, clearArea); } //Just to be safe, clear the perimeter at the end. data.FillPerimeter(false, data.BeingFilled); return(new XRegion(data.BeingFilled, data.Map)); }