Monday, November 6, 2023

Pool Rooms and Pool Rooms

When I say "pool room," do I mean a room with a pool table, or a room with a swimming pool? The answer is, both! I've added rooms with both pool tables and swimming pools to my scenes. I started with pool tables, and then later added swimming pools because I kept thinking about them every time I looked at the code. I'll describe how I added each type of room to 3DWorld's procedural buildings below.

Pool Tables

Some of the houses I've generated have quite a few unassigned rooms in the basements and extended basements. These are windowless rooms that don't work as bedrooms and some of the other room types. They're currently assigned functions such as storage rooms, laundry rooms, and card rooms. I've decided that a pool table would be a good fit for some of these rooms, at most one per house. I added code that picked the largest room and assigned it as a pool [table] room if it was large enough to fit the table with enough space around it for people to play pool.

I briefly considered trying to create an entire pool table with code, but I wasn't convinced it would look very good. Cubes can only go so far. Fortunately, there were plenty of free pool table 3D models available online. I chose one with the nice green felt surface and no other objects since I wanted to add the balls, etc. myself. The goal was to have a single table 3D model with a unique placement of pool balls and pool cues. I found a texture atlas image with all of the numbered ball patterns that I could apply to randomly placed spheres with random rotations/orientations. I added some couches to the room and a rug on the floor to get something like this screenshot. So far, so good.

Pool table with individual pool balls that the player can take. I have indirect lighting enabled because it looks much better this way. See the green reflecting on the ceiling?

Next, it was time to generate some pool cues. These are simple shapes made from truncated cones that I can already draw. I spent some time trying to find a pool cue texture online, but eventually gave up and drew my own in the Gimp image editor, using an image as a reference. Now that I had pool cues, I had to figure out where to place them. I decided to put a wooden cue holder on the wall with four slots, then place the cues randomly either in the holder, on top of the table, or on the floor leaning against the table. It took some extra effort to move the cues around as the player pushed or pulled the table. (Pool tables are too heavy for the player to pick up.)

Pool table with pool balls and pool cues in the holder, on the table, and leaning against the table. The balls are in different positions compared to the previous screenshot.

That looks pretty good. Each pool ball and pool cue is a separate object that the player can take and put in their inventory. I'm considering allowing the player to actually hit the balls around with the cues. I have most of the ball physics in place already, so it may not be that difficult. The main problem is that the pool table 3D model has complex geometry for the pockets that makes collision detection and physics difficult. It's not clear how to put the balls into the pockets. I'm leaving this as future work for now and moving on to swimming pools.

Indoor Swimming Pools

My original plan was to add only outdoor pools to residential yards. This mostly worked, but the system I have in place for exterior areas doesn't allow for as much detail as interiors. It also doesn't handle objects that extend under the terrain mesh such as in-ground pools. Plus, I really liked how the underground backrooms water from a few blog posts ago turned out. I did add water to bathtubs, but that's not quite the same because the player can't even enter them.

It's not easy to add water to above ground rooms due to the way they need to be cut into the terrain on the ground floor, and it doesn't make sense to have swimming pools on upper floors. That leaves basements and extended basements. House basements generally don't have rooms that are large enough to fit a pool. That leaves extended basements. This is convenient because I can reuse much of the extended basements water code from flooded backrooms to handle the water in indoor swimming pools. I've enabled underground pools for both houses and smaller office buildings that have no parking garages or backrooms. This allows me to separate the water logic between flooded backrooms and swimming pools because no buildings will have both.

The first step is similar to selecting pool table rooms, where the largest room is found and considered for a swimming pool. The main entrance door is determined, and the length of the room opposite the door is extended as far as possible up to a maximum distance or until an obstacle is reached. Obstacles include other underground rooms of this building, rooms of nearby buildings, and low points on the terrain. The room is also expanded by a smaller amount in width to allow for a larger (wider) pool and more space to walk around it. The room is rejected if the final size after all room expansion is too small.

The pool is then cut into the floor in the center of the room and takes up most of the space. A minimum of one doorway width is added along the sides, and two doorway widths along the ends. The end closest to the main entrance door has stairs added so that the player and building AI people can enter and leave the pool. The maximum water depth and number of stairs is determined by the length of the pool, and max depth is limited to one floor's height (about 8 feet). Pools above a minimum length have sloped bottoms with a shallow end at the stairs and a deep end at the far wall. Two or three gold colored metal railings are placed along the stairs.

I chose several shiny tile textures with normal maps for the walls, ceilings, and floors of the room, and the interior lining of the pool. The high specular component of the material makes them appear reflective and wet, and also helps to increase the overall lighting of these rooms. The ceiling and floor textures are the same at the moment. The wall texture looks exactly like the walls in the indoor pool room where I took swimming lessons many years ago. Water is drawn using the same shader to render reflections, refraction, and absorption that I used with flooded backrooms. I only had to tweak the constants to make it look good for swimming pools.

Here is what we have at this point:

Indoor underground swimming pool with shiny tiles on the walls, floor, and ceiling. Kind of plain.

That looks pretty good, but it's too empty. It's time to add beach balls and pool floats. I found a good striped color texture for use with large plastic beach balls. These are placed either in the water or off to the sides. These balls can be picked up, thrown, and kicked by the player. They float on the water surface and will rise to the surface if released by the player when underwater. They can be carried by the player to other rooms in the building.

Pool floats are modeled as simple torus-shaped inner tubes. I experimented with making them partially transparent, but I couldn't get the alpha blending/sorting to work between the water surface and multiple pool floats that may be visible through each other. I also considered using two sided transmissive lighting similar to what I used with tree leaves, but the current rendering and shader system didn't easily support this. So instead I opted for a simple small amount of emissive lighting in the color of the float's plastic to increase their brightness and reduce the shadows on their undersides. Pool floats can be picked up by the player but can't yet be pushed around or stood on. However, they have proper torus collision detection, so it's possible to throw a ball through their centers.

Here's a screenshot showing an example pool at this point in development. Notice that I've also increased the number of ceiling lights in pool rooms.

Brightly lit pool with pool floats and beach ball.

Pool with a float and two beach balls. This pool is in an office building, which is why the lights are rectangles.

That's looking better. Next I wanted to add some simple benches and a diving board to the larger pools. Maybe you wouldn't expect a diving board to be installed with a low ceiling underground pool though? And while I'm working on this, I may as well add a second pool inner surface material that's white with a rough finish. This is the style of the lining in the outdoor pool in my real back yard.

Diving boards caused some trouble with player collision detection because the system I had in place didn't support an object that could be walked on that was suspended above the floor. I eventually got this working, but the player can't actually jump off; they can only fall off the sides or end.

Pool with balls, floats, benches, and a diving board.

I was looking for diving board 3D models and found a nice model of a side pool ladder, so I decided to add those to the pools as well. I later went and added these ladders to the outdoor in-ground pools found in residential neighborhoods.

At this point I felt that the room looks pretty good. There were some minor fixes, such as reducing the period of the wave ripples and adjusting lighting inside the pool. It's time to move onto AI, player, and gameplay for swimming pools.

I would say the most difficult step was making zombies interact correctly with swimming pools. This actually took nearly half the total development time of pools! The default behavior without handling them was that people and zombies walked over the water like it didn't exist. The problem is that the water is actually under what would normally be the floor of the room. The AI system needs to special case handle the floors in these rooms by checking if points are over/under the water during path finding and physics updates.

It was relatively straightforward to have people treat the entire pool (including space above it) as a large collider to avoid walking into/through. This mostly worked, except for cases where one person pushed another over the pool when two people tried to pass each other on the narrow walkway between the room wall and the side of the pool. I had to add a check when the person was over the pool and have them fall into it with a smooth falling motion, rather than immediately dropping to the bottom in a single game frame. This was accompanied by a splash and ripple effect added to the water surface. Once they reach the bottom, a new target location is chosen as the closest point that's just beyond the pool stairs. The AI will turn and exit the pool in this direction. They climb the ramp and stairs to exit, and then revert to normal building room navigation when they're no longer inside the pool. I also added hard boundaries for the three non-exit sides of the pool to keep people from pushing each other through the pool walls.

Zombies proved to be more difficult than regular AI people since they follow the player. I had to change their behavior to keep them from falling in when the player was close to the edge of the pool or inside the pool. There was one bug that took me hours to fix where zombies intentionally walked into pools. I had to add debug printouts and debug visualization code to figure it out. The problem was that I had vertical wall collision objects along the sides of the pool to keep the player from walking through them when inside the pool. These were being picked up by the building AI navigation system even though they're not used for AI collisions. When the player was near the edge of the pool such that their bounding cylinder overlapped one of these walls, the zombie's target point was moved from the player location back toward the zombie location until there was no collision. This moved the target point inside the pool when the zombie was directly opposite the pool from the player. The fact that the path crossed through a blocking object (the pool) was ignored because the game logic assumes that if the player can stand there, so can a zombie. But this logic shouldn't apply when the target position has moved from the player due to collisions. The fix came in multiple parts: Ignore vertical pool walls, reject target locations inside of another object, and always enforce pool collision checks.

Zombies will still sometimes fall into pools, but it's not intentional. Usually it's because they're in a group pushing each other to get to the player. The zombie closer to the wall will sometimes push an adjacent zombie into the pool, particularly when cutting a corner. This is okay because there will always be at least one zombie outside the pool to chase the player.

Here's a screenshot of zombies having a pool party before I fixed the bugs. They try to follow the player, but keep falling into the pool. You can see the heads of a few zombies poking out of the water near the exit stairs on the far end of the pool.

Zombies in and around the pool. They try to chase me but keep falling in!

I decided to make the player "hidden" from zombies when fully under the water. When the player is standing in the pool with their head out of the water, the zombies can see them. But since zombies don't willingly enter the pool, they will simply walk around it and hang out by the stairs waiting for the player to exit. Zombies in the pool with the player will mostly ignore the player, but may attack when the player is located along their path and their head is out of the water.

I reduced the player's speed when walking (or swimming?) in water. The reduction scales with the depth of water around the player and reaches 40% when fully underwater. This isn't enough of a reduction to simulate real water movement, but a higher reduction makes it take too long to get out of the water when the player falls in. I already added a similar speed reduction for other cases such as when the player is climbing stairs.
 
The final step was to allow for player drowning when staying underwater for too long. This is mostly for game balance as it prevents them from hiding under the water until the zombies leave the pool area. I added an oxygen bar in cyan that only appears when oxygen is below 100%. The player has 30 seconds of air when underwater. When out of the water, the oxygen bar will refill completely at 10x speed, in 3 seconds. I increased the strength of the wavy water effect postprocessing shader as oxygen is reduced and made the screen begin fading to black when oxygen drops below 10% as a sign to the player that they're about to drown. Drowning will play a special gurgling sound and reset the player to the starting location with an empty inventory and no money.
 
I'm considering adding the player's dead body in the pool, if I can find a good animation or pose for that. It could even be a pickup item! I currently only spawn a pool of blood on the floor when the zombies kill the player. I guess they eat the player, or something like that? I'm not sure what happens to the items in the player's inventory on death. Maybe some items should drop? Only the item the player is holding at the time of death?

Here's a video showing how zombies and the player interact with swimming pools. I disabled the bug fix so that zombies fall into the pool because this is more entertaining to watch. Of course it also makes gameplay too easy.


Now that I have swimming pools with nice blue water, the water in flooded basements seems too clean. I changed the backrooms water material to be 50% mud to give it a dirty brownish color, and the increased variety looks much better. Here's a new screenshot for reference.

Flooded backrooms with muddy water.

Everything is working well now. I may add some sort of player swimming ability later if I can find a good way to control it with the keyboard. I might also try to improve outdoor pools and actually allow the player to enter them.

6 comments:

  1. Hey Frank its me again. i've been following your progress over the past few years and i must say i'm glad to see you still working on your project I compile and run it semi-regularly to check out new features each month or so. There are a few things i've been wanting to ask as far as features would go for the generation. That i feel could be really cool and could spice things up.

    One being is it possible to you could add a feature to the generator that allows walls to be non uniform. For example rooms that are not limited to a plain rectangle or square shape. And allow them to have a more irregular/natural fitting. It would give interior rooms in residential buildings a more natural feel allowing L-shaped rooms and such. Though this could require a large refactor of how walls are divided and such.

    Some rough examples that are interesting

    https://interiorharmonyblog.com/2020/02/23/feng-shui-conversation-a-room-with-a-challenge/

    https://www.fromhousetohome.com/l-shaped-living-room-layout-ideas/

    https://www.pinterest.com/pin/340303315605689497/

    This could be really interesting of it pans out. the biggest gripe in terms of interior variety for houses especially is the room structure feeling a bit too predictable . It doesn't have to be on on the scope of that last example for sure but i included it just for a general reference.

    this "could" even lead to a new way of gen-ing homes if it does work out. i know modrn minimalistic homes can be shaped and structured in any way you'd want them. allowing for irregular exterior structuring


    The second suggestion i have is for a new location type. A generic storefront. Say a small local market/grocery store. it sounds as it could be relatively simple. Generating a entrance into the main store section with misc objects like racks with objects and such. And then a back storage area and restrooms. Something like that could be really cool to see.

    And that is all! Lastly as a sort of side thing depending on if you decide to take either of these suggestions on. I wonder if it could be an opportunity to experiment with each floor of a residential home being a sperate floor plan. As an experiment that's toggleable. i'd actually like to try it out with a small amount of houses like 200 of them or so just to see how it effects performance or so.

    But it's great to hear from you in general and any response is well appreciated!

    ReplyDelete
    Replies
    1. (I can't sign into my Google account for some reason to comment.)
      For non-rectangular rooms, I already have some of these in office buildings. There are non-rectangular hallways, backrooms areas, curved wall rooms (in cities), and some complex floorplans where wall placement failed. I don't have any of these in houses though.

      The primary challenge is that the AI path finding uses a rectangular room/door graph for navigation. It may be possible to work around this by having two adjacent rooms with the wall removed rather than wall segments plus a door. This would still be two rooms rather than one, so it wouldn't be possible to place objects for a single room across both parts of an L shape, for example. However, most of the floorplans in your links are in fact two rooms connected together. Usually this is living room + dining room, or living room + hallway. It should be possible to remove the wall + door between some living rooms and adjacent public rooms.

      For storefronts, this is more difficult. There's existing research out there for generating the interiors of houses and office buildings. I've never seen an example of a procedurally generated store. I think the problem is that there's both too much variety and too many constraints. It's difficult to create a floorplan with enough variety while also making it look valid. A second problem is that there may be too many objects in a single room to get acceptable performance. If I added a large front "showroom", you would expect to see many items in rows on racks or shelves. This also requires a whole new list of interior items that's different from what I have for houses and offices. While it may be possible, I would expect this to take significant effort. Maybe sometime in the future.

      For residential floorplans, I do have some buildings with different floorplans on each level. The biggest problem here is that it can be difficult to place stairs that are valid and don't intersect the walls on either the floor above and the floor below. The high rare of stairs placement failures made me disable this in most cases. It could still work for multi-family houses where the doors are on the upper levels and the interior stairs aren't needed. This addition was relatively recent.

      Thanks for the suggestions!

      Delete
    2. Thanks for the reply frank! And yea i do agree on that last bit. It would only be possible to have different floorplans for each floor in theory if the stair rooms are to be generated in the same position across every floor. That could be a complete nightmare or headscratcher to say the least.

      Delete
    3. I added an option that will sometimes split office buildings into two different stacked vertical floorplans. Houses sometimes already have stacked parts, though it's somewhat rare. The code supports it. These buildings are less efficient though, which is why they're not as common and there's only one split.

      I looked into connecting rooms directly without doors/walls to get non-rectangular shapes. I first tried this with living rooms and the room they connect to. This doesn't work for multi-floor houses because the current graph connectivity system can't handle two rooms that are connected directly on the floor below but have a door + walls on the floor above. The connectivity is share across all stacked floors. I have to split these into stacked parts with the ground floor in a separate part from the upper floors. I'll have to get back to this later.

      Delete
  2. Cool addition! I feel the ceilings are too low, and it makes the pool room feel claustrophobic. The light shape indicating the building type is a nice touch. Are you planning to add a Jump mechanic at some point?

    ReplyDelete
    Replies
    1. I agree. Since these underground rooms have no exterior and aren't vertically stacked, I can make them any height. I already changed some of the pool rooms to have higher ceilings. But this only works when there's space above and the ground isn't too close, so you only see it on offices with multiple basement levels and houses at the base of hills.

      I have jumping enabled in a different gameplay mode, but not for buildings. That mode works with hand created levels. I worry that jumping in procedural buildings would result in the player getting stuck, since it's difficult to determine where a player can go when jumping is allowed. And I would probably have to make the zombies jump as well to be able to reach the player.

      Delete