Doesn’t follow any logic other than Min and Max Room sizes. with a little bit of randomization around where the split goes.
I want to create some more solid rules.
Ensure Rooms have Purpose (bedroom, kitchen, living, etc). with support for multi-purpose rooms when the room cannot be split.
(E.g. House with 1 room will be a bedsit (Bedroom / Kitchen /Living merged into one)
Ensure House fulfills minimum requirements in order.
Bedsit < Studio < 1 Bed Flat < and so on until size is big enough to have specialized rooms.
I think the City Zoning blog post will be of great help for this as you can start splitting the house into zones after it gets big. (Sleeping Areas / Living / Recreation / Utilitarian areas, etc). And create a ruleset to classify and then choose how to generate the content.
It took me a while to update this, but I can subdivide a space into a series of interconnected rooms.
Right now the Door Sizes are fixed, but I have built-in the ability to randomize the passage width, add a frame or not, so this should create more interesting layouts.
I’m not sure about the believability of the logic though, because it can generate some awkward layouts.
I want to logic to go to a hierarchical structure as mentioned before, so the room splitting will be a bit more deterministic (layouts less random), but I’ll have to figure out how to keep the variety going. I’m reading a couple of white papers on these that are interesting.
But overall I’m happy I managed to get a series of interconnected rooms.
Yeah, it’s starting to look convincing. Buildings will normally have other constraints like supporting columns, stair-wells, service risers, lift shafts, etc, so it’s bound to look a bit ‘random’ with full freedom to divide the space up. This is a great rabbit-hole to be going down though. I’m sure you’ll find yourself thinking of ever more tweaks you can do to improve the logic.
Added random twists, and now I’m getting a better distribution.
I need to add randomness to the decision of splitting a room. right now I have Must Split / Can Split, and it will do it. And it always splits the room across the longest axis.
Not sure how you’re doing it, but I added a special operation a while ago to help with room splitting:
Numerical.MergeRanges - Combine arbitrary list of numerical ranges into a list of non-overlapping ordered ranges
Basically to help find all the places along a room that don’t intersect a door. It’s quite specialised, but useful as it’s a number-crunching process that is very complicated to implement as a procedure. You would use it by building a list of pairs of start/end of all the doorways along the room in one axis, it will output a similar set of values but each segment will be non-overlapping and they will be in order. This makes it easier to scan for ‘gaps’ that a split can safely happen in.
I added this when I wanted to add vertical shafts to my dungeons, and since these are areas (like doorways) that can’t be split (but in both axes) it was going to make the logic I already had horribly messy, in-fact I don’t think I could get my head around it. Anyway, I wrote this operator to do the heavy lifting instead.
What I did was start with a Main Room, add doors on each side at random places. Then get the right, middle and left frames, and start splitting them.
That’s why you’ll always see one or two long corridors. I did that because it’s consistent with some early design inspirations of how houses are split.
it looks weird for these huge buildings, but it feels a little more natural for “normal” house sizes.
When a room is split, it adds a Connection wall where the split has happened. The problem is that right now my room splitting logic doesn’t have any knowledge of where doors exist (unlike the main room).
I could recurse the Main room logic instead because that already only allows for splits outside of areas that have a door (but I got a bit bamboozled by my own spaghetti)
I need to improve (or rethink this), because this does not guarantee that the walls won’t land where a door already exists, I think perhaps that’s where Numerical.MergeRanges Would come in handy, though I’m not sure I understand how it works.
Ah, no, still lacking detailed docs on all the operators. Probably going to need that for release aren’t I.
But, yes, that’s exactly what I used it for. Although its only part of the process. Something like this:
Lets assume we are wanting to split a room into a left and right part, and have doorways along the top and bottom.
Work out the distances of each door from the left side, as a min/max range (I.e. the leftmoay side and rightmost side).
Collect these into a list of floats, alternating left, right.
Pass into merge operator.
Go through the result, adding up the amount of space that isn’t covered by doors across the room. This is the space you could split the room.
Now choose a split value within this amount.
Go through the list again, counting up sections until you get to the one with your split point in. Calculate where this is within this section, and thus where across the room it is.
This is where you split the room, and insert a wall.
All doors need to be assigned to the appropriate new sub rooms. Including any newly added doors on the new dividing wall.
If there are no doors on one side you either have a dead-end room, or don’t have to insert a door to leave a dead-space.
This explanation would be aided by a diagram or two. Some of this might be covered on the old blog posts I made actually. Check the About/Archive section on the website.
In terms of insuring rooms have a purpose, I know I saw a paper a while back that got into this based on recognising that there are broad categories of linked purposes for rooms, and that the easier it is to get to a room, the more ‘public’ that purpose is. I can’t find the original paper, but I found three others that seems to touch similar areas:
I went back to this thread after the conversation we had this morning and then I re-read the post about the Numerical.MergeRanges Operator so I decided to test.
The ConnectingWall procedure is outputting the “location” of the door packed into the Vector3 (being X the split amount, and Y the split amount plus the door width.
Then I’m running these Pairs of floats, into the Merge Ranges
and I’m getting either 4 numbers or 2 numbers.
I get 4 numbers when the doors are not in front of each other
I get 2 numbers when the doors ARE in front of each other.
Sounds like you have it right. The returned list is where the doors are. If you mentally add a 0 to at the front of the list and a [Wall Length] at the end then the list can be considered a list of pairs wall segments instead, where you can split.
i.e. -------[ ]----------[ ]---
becomes [------] [----------] [--]
A simple way to choose a split point is then:
Randomly select a wall segment
Select a random point along it’s length
Split there
However, this is biased in favour of shorter segments. If you want to properly select a place among the wall segments you need:
Awesome, it’s great when you crack a hard problem and then everything ‘just works’, especially with proc-gen where you can then go crazy with trying things.
Observations:
Extra doors would come from adding multiple doors on long split walls, i.e. aiming for some min spacing between adjacent doors perhaps.
The exterior rooms are those that have any openings tagged as windows (unless you allow interior windows, but you could tag them as a third opening type).