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));
    }
Пример #4
0
    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));
    }