5
\$\begingroup\$

I've made a fairly simple dungeon generator but now I want to expand on it so that I can procedurally generate a dungeon with irregular shaped rooms. I don't just want any old crazy shapes popping up though, I want to be able to have room types that follow a certain pattern but ultimately have random sizes. I just don't have a clue how to generate rooms that aren't just square.

I have an idea of how to merge squares together to make rooms comprised of other rooms, but I'm more interested in how to get hexagon and octagon shaped rooms, or doughnut-like rooms. My code for generating square rooms is:

    public static char[,] GetSquareRoom(int width, int height)
    {
        char[,] roomLayout_Square;

        roomLayout_Square = new char[width, height];

        for (int x = 0; x < roomLayout_Square.GetLength(0); x++)
            for (int y = 0; y < roomLayout_Square.GetLength(1); y++)
                if (x == 0 || y == 0 || x == width - 1 || y == height - 1)
                    roomLayout_Square[x, y] = '#';
                else
                    roomLayout_Square[x, y] = '.';

        return roomLayout_Square;
    }

I would like to create more functions like this that will accept a few variables so I can create specific variations of these room-types, so I can input specific number and randomly generated values alike.

:)

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Yet again I thought I'd share a vaguely related link: Irregular Shaped Rooms (from roguebasin). If anything, it may help as inspiration. \$\endgroup\$
    – Roflo
    Oct 22, 2015 at 14:58
  • \$\begingroup\$ @Roflo - I was actually looking at this yesterday, a very neat way of generating completely irregular rooms. A few of these might actually look good in a procedurally generated dungeon, no? Or perhaps the method can be altered to create somewhat less irregular shapes? Your knowledge of vaguely related links is endless, thank you :) \$\endgroup\$
    – georgeous
    Oct 23, 2015 at 10:35

2 Answers 2

4
\$\begingroup\$

You can create a room that is in the shape of a regular convex polygon with arbitrary sides, size and rotation.
Steps:

  1. Draw walls by picking pairs of points around a circle and linearly interpolating between them. The number of pairs should equal the number of sides of the shape. You will need to use trig for this.
  2. Create a floor by filling the shape using some sort of fill algorithm.

You can then create a doughnut shaped room by subtracting a smaller generated room from the center of a larger generated room. You should keep the walls of the smaller generated room though.

Since I found this interesting I went ahead and tried implementing it myself. I would recommend not looking at my code until you have tried to write it yourself though.

public static char[,] RegConvexPolyRoom(int sides, double radius, double rotation)
{
    // convert the rotation degrees to radians.
    rotation *= Math.PI / 180.0;

    // make an array size that is sure to fit the room.
    int roomSize = (int) Math.Ceiling(radius*2) + 1;

    char[,] room = new char[roomSize, roomSize];

    // first we must create the walls of the room.
    double rchange = (Math.PI * 2.0) / sides;
    for (double r = 0; r < Math.PI * 2; r += rchange)
    {
        // define first point.
        double p1_x = radius + Math.Cos(r + rotation) * radius;
        double p1_y = radius + Math.Sin(r + rotation) * radius;

        // define second point (rotated 1 iteration further).
        double p2_x = radius + Math.Cos(r + rotation + rchange) * radius;
        double p2_y = radius + Math.Sin(r + rotation + rchange) * radius;

        // get distance between the two points.
        double len = Math.Sqrt(Math.Pow(p2_x - p1_x, 2) + Math.Pow(p2_y - p1_y, 2));

        // linearly interpolate between the two points and place walls between them.
        for (double i = 0; i < 1; i += 1.0 / len)
        {
            int place_x = (int) Math.Round((1 - i) * p1_x + i * p2_x);
            int place_y = (int) Math.Round((1 - i) * p1_y + i * p2_y);

            room[place_y, place_x] = '#';
        }
    }

    // now we have to fill the room with a floor.
    // this is done using something similar to a scanline algorithm.
    for (int scan = 0; scan < roomSize; scan++)
    {
        int left_x = -1;
        int right_x = -1;
        bool spaceDetected = false;

        for (int i = 0; i < roomSize; i++)
        {
            if (room[scan, i] == '#')
            {
                if (!spaceDetected)
                    left_x = i;
                else
                {
                    right_x = i;
                    break;
                }
            }
            else if (left_x != -1)
                spaceDetected = true;
        }

        if (right_x != -1)
        {
            for (int i = left_x + 1; i < right_x; i++)
            {
                room[scan, i] = '.';
            }
        }
    }

    return room;
}

Here is a hexagonal room generated with the above method:

     ##############
     #.............#
    #..............#
    #...............#
   #................#
   #.................#
  #...................#
 ##...................#
 #.....................#
#.......................#
#.......................#
#.......................#
 #.....................#
  #...................##
   #..................#
   #.................#
    #...............##
    #...............#
     #..............#
     #.............#
      ##############
\$\endgroup\$
2
  • \$\begingroup\$ Thanks for the answer. The ring room implementation seems really interesting though, can arrays be altered like that? I thought to do that with the square rooms I have generated, i.e.: create large square room, then small square room, and then subtract the small room from the large one's centre but I have no idea how to do this when working with arrays. \$\endgroup\$
    – georgeous
    Oct 22, 2015 at 12:37
  • \$\begingroup\$ Nevermind, managed to create a nice 'hole room' function that takes room width and height, and hole width and height, but all the time allowing at least a 2-cell path width round the hole. A couple of horrible if statements though. Thanks! \$\endgroup\$
    – georgeous
    Oct 22, 2015 at 13:45
3
\$\begingroup\$

If anyone is coming across this and wants to make non-regular, square dungeon rooms, you can still use Quintin's answer just adapted a bit.

You will move along the circumference of a circle until you reach 360 degrees(2 pi radians), back to the starting point. (you can use either radians or degrees, I will use degrees for readability. Keep in mind math functions use radians. convert with degrees * pi/180)

Create a loop starting at 0 degrees around the circle and stopping at 360 degrees. Each loop you will do the following:

  1. Generate a random degree amount and increment the total degrees by it. Use whatever range you want, smaller values = more circular and more corners, larger = more boxy.
  2. Use x = radius * cos(angle) and y = radius * sin(angle) to get an x,y position (relative to the center of your circle/room). If you are using degrees you need to convert degrees to radian with degrees * pi/180
  3. Fill in the walls from the previous position to the new one.
  4. Set the previous position to the new one and move on to next iteration

Filling in the walls from the previous to new position is simple. Get the difference from previous to new position with new - previous (that order). Then you can draw the x wall and the y wall by moving that distance along the respective axis.

And that's it. You may need to do one final wall filling from the last position to the very first position.

Here is an example room I made with a tile based map. The random degree change range was 20 to 90 degrees, with a radius of 10 (tiles). Example Room

And here is a circle overlay to show how the points along a circle's circumference are used to make the room: enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ 8 years later and this is a great solution I haven't come across. You might want to hard-limit the degrees to be less than 90 so that you can always guarantee that the room's walls don't close in on themselves. \$\endgroup\$
    – georgeous
    Nov 23, 2023 at 22:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .