Wednesday, May 31, 2023

Procedural Buildings: Breakable Objects and Particle Effects

I have a long list of smaller additions and improvements to show, so I'll split them up by category. This post will show some of the breakable and broken objects I've added to buildings, and the particle system I implemented to add glowing spark effects to broken electrical objects. Some of these have been around for a while, while others were recently added.

Broken Car Windows

I added the ability for the player to break into parked cars in office building parking garages to steal items. This was done a year or so ago, but I don't remember posting a screenshot or explaining it on this blog. Each car window can individually be broken once by using the player action key on the car. Some cars happen to be unlocked and can be looted without breaking the window. I can't easily modify each instance of the car's 3D model to remove a window, but I can draw a pile of broken glass on the ground at the player's feet. As you might expect, each pile of glass is unique. This glass will remain in the building forever to help players keep track of which cars they've already broken into. This was an easy change to make. I may decide to go back later and make the glass shards dynamic physics objects, or possibly allow the player to pick them up for some gameplay purpose.

A car in a parking garage with broken glass from the window on the ground.

Broken Mirrors

Throwing an object at the center of a building mirror will break it and add a crack decal texture over the reflective surface. One of two crack textures is randomly selected for each mirror. This works with dresser mirrors, office bathroom wall mirrors, and house medicine cabinet mirrors. While the player can drop various types of inventory items, the only object types that can be thrown are basketballs and soccer balls. Therefore, these are the only objects that can be used to break mirrors and other glass surfaces.

Breaking mirrors plays a loud glass shattering sound, which of course is guaranteed to attract zombies. Breaking a mirror also unlocks the "7 Years of Bad Luck" achievement.

Mirrors can be broken by throwing balls at them. Broken mirrors are cracked but still reflective.


I've considered making windows breakable, but so far haven't figured out how to do this. Windows aren't individual objects but are instead drawn along the entire side of the building, and are visible through cutouts in the walls. I would need to split these up into individual window panes somehow, then add the crack texture to each broken one. Some of the house windows are already divided vertically or horizontally into 2-4 panes, which further complicates things. A second challenge is adding a transparent overlay to an object that's already transparent in a way that makes the alpha blending correct. Of course, writing about it here will increase the likelihood that I actually complete this feature later.

Broken TVs and Computer Monitors

The player has been able to throw balls at TV and computer monitor screens to break them for a while now. The new feature to showcase is the particle system I've added that will spawn glowing sparks around the area where the ball and screen meet, as long as the device was powered by electricity. These sparks are physics objects affected by gravity with collision detection enabled for all room objects. I was able to reuse most of the basketball and soccer ball physics and collision code for particles, with some adjustments to physical constants to make their paths more pleasing. For example, sparks use lower gravity so that they remain in the air for longer.

Each broken object spawns a new group of particles that will disappear after their lifetime expires, which is currently set to a few seconds. This way only a small number of particles will be active at any given time and won't affect performance much. Sparks are drawn with an emissive colored material stretched out along the length of their velocity vector. Their color follows the normal black body light emission profile as their temperature decreases over their lifetime: white => yellow => orange => red => black. Light emission decreases over time, and transparency increases.

Later I decided to make these particles act as small light sources to illuminate the walls, ceiling, floor, and other nearby objects. The screenshot shows light sources, while the (older) video was taken before this was added.

Still screenshot of a TV screen that's just been broken with a basketball, with sparks flying around the room and producing light.

 
 

Broken Lights

There are two types of broken lights. A while back I added flickering lights with a random chance to occur in basements and parking garages. These lights are mostly on but turn off for a few frames every few seconds.

The new type of light I added is even more broken: normally off, with an occasional flash of light and a continuous shower of sparks. This was a convenient way to reuse the particle system I developed for TVs in a setting where the sparks are constantly visible, rather than only being seen briefly for a few seconds. These types of lights are only added to house extended basements rooms, giving them a dark and creepy atmosphere. Broken lights are always initialized to the off state and must be turned on by the player to make them active. This increases the amount of surprise when the player encounters a shower of sparks rather than a lit room. So far I haven't decided if I want the building AI people to turn these lights on as well.

Still screenshot of a broken light emitting glowing sparks that fall to the floor. Maybe they should catch the rug on fire?


It's possible to have a large number of broken lights in a building due to the way occlusion culling works. Since they're conveniently only added to basement rooms, I don't have to worry about them being visible through windows. The player can only see the lights and the sparks when the clipped light volume is visible. This means I can reuse the existing light bounding cube occlusion queries to skip generating, updating, and drawing the particles when the light is blocked from view by a wall, ceiling, or floor of the building. As soon as the player turns to leave the room or walks around the corner, these lights will become inactive and won't take any resources to draw or update.

Future Work

Broken lights don't really affect gameplay, except for reducing zombie (and player) visibility due to the dark room. Maybe I should have sparks catch rugs on fire? It sure seems like that rug should be bursting into flames in the screenshot and video above. That could damage the player and also either distract or kill zombies. Okay, I'm adding that to my TODO list.

I have plenty of other ideas for breakable objects. I could add a tool such as a crowbar, hammer, or bat that can break objects. I could allow some inventory items such as cups and vases to be dropped or thrown on the floor to break. I could provide a way for the player to create holes in the walls, ceilings,  floors, or doors. There are so many possibilities. I need to take some time to think about how gameplay will work and the various ways in which breaking/destroying objects would benefit the player.

Monday, May 8, 2023

Procedural Buildings: Connecting Basements

Some of the houses in 3DWorld have extended basements consisting of a maze-like tree of underground hallways and rooms. These can run under the house and nearby buildings, as long as no other buildings are intersected. I like these mazes. I like anything involving underground networks to explore where the player can get lost, in particular in a horror game setting. The current limited size of each house's extended basement prevents me from adding larger mazes. It's not just a problem with available space, it's also a problem with reduced performance when adding too many rooms to a house or making it's bounding cube too large. The various building view culling methods I'm using are less effective when many buildings overlap in 3D space.

One workaround for this is to allow basements to connect between multiple houses. In fact, they can connect together in a massive dungeon maze that runs under the entire residential neighborhood. This case is made easier because all houses are at the same elevation, so I don't even need to add stairs to connect rooms at different levels. I decided to start by grouping houses by city, and attempting to connect each house in the city to every other house placed after it. This is quadratic in runtime, though only for a few hundred houses at a time since they don't all have extended basements. The final runtime for this step was only 19ms for all four residential cities combined. I didn't even have to make the code multi-threaded.

If two nearby rooms that project in X or Y can be found for each of these houses, a new hallway room is added to connect them. I cut a hole in one of each of the room's walls to insert a door. I placed a red light on the ceiling of this room to make it stand out more. This way I can find and debug connector rooms by disabling collision detection and flying below the ground looking upward for the red lights. I'm glad I added this for debugging because I certainly found a lot of problems with this system! Every room had some new bug. I'm sure I haven't found and fixed them all yet.

The only downside is that this was very complex and difficult to get right. Not only does it need to look correct, but the AI and physics must work as well. On the visuals side, I had to make sure the occlusion culling didn't flag the other house as invisible as it normally does with other buildings when the player is underground. Then I had to work out the lighting and shadows so that the connector room could cast and receive both light and shadows from the rooms of the two houses that connected on either end. These had to be updated when the user toggled the lights or opened/closed the door from either side. In addition, the ambient lighting system had to consider light coming through the open connector door.

Physics was also quite challenging. I had to update the player collision detection to allow walking between buildings without being blocked by the basement bounding cube, and without the player being considered outside a building for one frame and popping out of the building on the ground above. This last problem took me many attempts to fix! In fact, I think it can still happen in rare occasions when a building person or zombie pushes the player into a wall near the connector room.

Players had to be able to open or close the connector room doors from either side, which means I had to support interacting with a door belonging to a different building from the one the player was inside. Next, I had to allow the player to carry inventory items between buildings without them being deposited in the player's permanent loot collection as would normally happen when exiting a building. Building animals and people AI were updated to handle these connector rooms. I didn't quite figure out how to have them cross between buildings, but at least they don't get stuck there. Zombies will follow the player right up to the connecting door and wait for a few seconds before walking off. This provides the player with an escape route. I think that's fair because it's far too easy to get cornered or lost while being chased in a basement maze. However, chances are some zombie in the other building heard you and is on the way to find you.

Probably the most difficult feature was adding support for basketballs and soccer balls that could be rolled, kicked, or thrown through the doorway into the next building. These objects have physics state owned by their contained building. I had to transfer this state from one building to another in a way that preserved the properties such as position, velocity, and momentum. There were various special cases to handle. For example, the player can stand in one building while holding the ball through the doorway into the other building. The physics must be seamless across the boundary.

Here are some examples of extended basement connector rooms.

Extended basement connector hallway with red light, a picture on the wall, and a rug on the floor.

Hallway connecting one house basement to an underground storage room in a different house.

Room connecting two house basements. You can tell that the connector room belongs to the building the player is in because the carpet matches.

They look very similar, especially with the red lights. At the moment this is a somewhat intentional way to let the player know they're passing between buildings. There's also a "Welcome to <NAME> Residence" text to let the player know whose house they're entering. Maybe I should select a random light color from a list of colors? I'm not sure. I experimented with different colors and I definitely like red the best because it produces a sense of danger and has a good contrast with the off-white color of other ceiling lights.

What's next? Maybe I'll figure out how to have people and animals cross between buildings. Maybe I'll connect office building basements and parking garages in a similar way. There are so many possibilities...