Monday, July 31, 2023

Stacked and Multi-Family Houses

I've recently put a lot of effort into improving building interiors by adding new types of objects and other details. Now it's time to revisit exterior geometry and room assignment, in particular for houses. I wanted more variety in house geometry, so I added a new type of house that has a smaller cube stacked on top of a larger cube. Then I made some of the larger houses multi-family homes split by floor. I'll describe these two additions below.


Stacked Houses

Houses initially came in two general floorplans, a rectangle and an L-shape. The L-shaped houses were formed from two rectangles placed next to each other with possibly different heights. This formed either an L-shaped floorplan, an L-shaped exterior vertical profile in cases where heights were different, or both. Each floor had the same floorplan so that a single set of vertical walls extended through all floors, and a set of stairs connecting them. Some houses also had rectangular basements, and some of those had a network of extended basement hallways as explained in this blog post. The combination of different heights, aspect ratios, roof styles, garages, sheds, porches, chimneys, etc. added a lot of variety to these otherwise simple shapes. However, I wanted to add even more house variety.

I've already created some styles of office buildings that have vertically stacked sections, where the upper stacks usually had a smaller footprint. There are some overhangs, but these are rare. This same stacking approach can be applied to houses, allowing me to place a smaller cube on top of a larger cube. Both the upper and lower cubes can have multiple floors. I added a 50% chance that each of the four sides of the upper cube is shifted inward to create a smaller footprint. If none of the four sides are moved, we simply end up with a single cube that has two different interior wall floorplans for the upper vs. lower levels. This is fine too as it adds variety to house interiors.

Here are some examples of houses created with this approach. These next three screenshots show houses with a combination of one, two, and three inset sides.

Two stacked part houses: Foreground house has a tall and narrow upper part; Background house has a small sloped roof section over one side of the lower part.

Two more stacked part houses next to each other, viewed through the power lines. Note that all houses in the same block use consistent exterior materials and styles.

A house with a wide bottom floor with garage, and a narrower upper part.

This was quite a bit of work to implement. I can't remember everything I changed, but it must have been over a dozen blocks of code. There are some obvious additions such as the custom sloped and overhanging roof quads on the lower cubes of the houses.

Note that the original version of these houses had steeper roofs on the lower parts, but I couldn't get the windows to look right. Removing the windows from the inset walls on the floor above the wider bottom parts created windowless rooms and caused other problems. While I did prefer the exterior look of theses houses, I just couldn't get the interior to be correct in enough cases.

The attic code had to be modified to only add attics to the upper parts of these houses. That change was relatively easy. What really got messy was adding stairs. Keep in mind that stairs are placed after adding walls and interior doorways. In some situations it was possible to add a single stairwell that extended all the way from the ground floor to the top floor without hitting any obstacles or blocking any doors. In other cases there was simply no valid location to add stairs, so stairs had to be split into two or three sections that were placed in different rooms. For example, the house in the foreground of that first screenshot has three sets of stairs: one connecting the bottom two floors, a second connecting the top three floors, and a third connecting the bottom part to the top part. Oh, and there's also a fourth set of stairs connecting the ground floor to the basement. The logic to place all of these stairs is quite complex and was difficult to implement. Updating the building AI (zombie) logic to navigate using these stairs also took some effort to get right. I actually had code in place to handle multiple sets of stairs, but it was broken in a way that wasn't triggered by the multiple sets of stairs that already existed in office buildings.


Multi-Family Houses

3DWorld's generated houses are typically smaller than office buildings, both in height and in their terrain footprint. Of course there can still be large houses. This usually happens with single cube houses rather than L-shaped houses, because the cube can fill the entire lot with no space cut out of it. Sometimes a house is generated at the max height of five floors and also near the max width in both X and Y. These are unrealistically large for a normal single family home.

For example, we have this monster house shown below. It has five floors with 17 rooms per floor, for 85 total rooms. There are 38 bedrooms and 8 bathrooms. My entire living family tree can stay in this house!

This house is too large for a single family, so I split it by floor into a five family apartment building. You can see the vents from all of the kitchens on the roof.

The solution is to split houses that are both wide and tall into multi-family homes. These can be anywhere from duplexes to small apartment buildings. The simplest solution was to assign one family to each floor and keep the same floorplan for each level. Here I mean the same walls and doors. The room assignments can be different, and they generally should be different, at least for the ground floor entry area.

This required significant changes. The most obvious change is that each individual apartment should have at least one bedroom and one bathroom, plus a living room, dining room, and kitchen when possible. This means that living rooms, dining rooms, and kitchens are no longer constrained to the first floor. Of course only the ground floor resident will have access to the basement (if there is one), but that may be okay for now. Room assignment is quite different, with some new constraints.

The second change was related to the front door placement. Regular houses usually have the front door connecting to either a small entryway room, or to the living room. However, it doesn't make sense in multi-family houses that someone should walk through the ground floor resident's living room to get to their upper floor apartment. No, we want the front door to connect to the room with stairs instead. If this isn't possible because the stairs room has no exterior wall, then the next best room for the front door is a hallway connected to the stairs room. Since hallways cross the entire part, and cube-shaped buildings only have a single part, we can place the door at either end of the hallway. Most of these larger houses already have a hallway, and most hallways connect to the room with the stairs. It should be rare to have stairs in a room that's neither along an exterior wall nor connected to a hallway. So far I haven't seen a house where this approach failed.

The above door assignment algorithm still has some flaws. In some cases the room with the stairs is assigned a function such as a living room, or it's not possible to reach every room in the house without crossing through the public stairs area. In fact the stairs room often has multiple doors, rather than the single apartment front door we would expect. I think I would have to go back to the floorplanning step to fix this. What we would really need to solve this is a dedicated entry + stairs room that connects to the front door and has exactly one door leading out to the rooms on each floor. Or we could possibly have an exterior stairwell with front doors above the ground floor. That could work, but would require significant code changes.

The third change I had to make is related to family names shown when the player enters the house. I kept the main generated last time for the ground floor tenant. This is what's shown on the sign above the front door (if present) and what's printed when the player enters the house from an exterior door. I used the hash of this name as a random number seed to generate different family names for the other floors above the ground floor. This is shown when the player uses the stairs to move to a different floor. The building's address and other string properties remain unchanged.

This system isn't perfect. Sometimes it's not possible to assign the required room types to each floor. Sometimes an exterior door can't lead to the room with stairs or a hallway connected to stairs. There are other ways of creating multi-family houses that avoid these problems, at the cost of introducing a different set of problems. For example, another approach I considered was to create duplexes by placing either two mirrored houses next to each other, or two symmetric parts (cubes) of the same house next to each other. This would make it easier to ensure the room assignment and connectivity requirements were met. Each part of the house could have its own front door without needing to connect through stairs.

This solution is more difficult to implement because it requires changing the exterior geometry and wall floorplan to work with duplexes. I would need to add logic to handle shared walls between units that doesn't assign windows or doors to these walls. There's also no easy way to guarantee symmetry for the two houses in the current procedural generation system. It's unclear how much better this would work and what other problems might arise. I decided it's too much effort to experiment with this approach since it's not an obvious improvement. I may change my mind about this later, so there may be a future post on this topic.

2 comments:

  1. It's fascinating how the room assignment works, really backing in to the interior. Normally, an architect would design the building from the inside out, starting with the entryway and the stairs and then the kitchens and bathrooms before doing bedrooms and lounges last. This procedural system seems to run in reverse of the normal approach, but it still works!

    I've seen a lot of multi-story appartments with exterior stairs, usually with a central stairwell serving two "wings" of apartments. That way the "front door" is still the only door into each apartment, and you don't have to worry about entering the ground floor living space. A lobby would be another approach, though that's more common with hotels and dorms.

    Even so, neat that it's mostly working with the existing code structure!

    ReplyDelete
    Replies
    1. I had to generate buildings like that so I could draw the exterior of distant buildings without needing to do the expensive interior generation first. I think it produces buildings that are somewhat odd and nonstandard, but I'm happy with the results.

      I wasn't able to add objects such as exterior stairwells until I added these exterior objects. I still have to figure out how to handle the player logic. Is a player on exterior stairs inside a building or not? How does the lighting work? It's also not clear whether it's easier to have a single "house" with the stairs in the middle and 2+ apartments, or two different houses with some sort of shared all and stairs. Some office buildings already have lobbies.

      Delete