Sunday, March 7, 2021

Procedural Buildings: AI and Player Interaction

I'm in the process of working on my game where the player steals items from houses and office buildings that are infested by zombies. The goal is to have both the player and the zombies interact with objects inside the buildings as part of gameplay. This includes entities such as room lights, doors, pickup objects, items on the floor, drawers, etc. Most of the items placed in rooms have been static up until now, but I want to make almost every object be interactive. That means the player must be able to pick up, drop, move, open, close, etc. the various room items. AI People inside buildings will also interact more with objects, even if that only means better object collisions and physics.

Here are some of the interactions I'm working on. Sorry, I don't have too many pictures for these. This is mostly a list of concepts and ideas I'm working on implementing for gameplay. I'll probably post some YouTube videos of early gameplay a bit later. At this point I have the high level gameplay system written, it's just a matter of filling in all the details.

Lights

Every room and hallway has one or more light placed somewhere on the ceiling. In addition, some bedrooms have lamps placed on nightstands and dressers. I recently added small lights to the ceilings of some of the walk-in type closets that the player can enter. Each of these lights can be toggled on and off by the player. This feature has been around for a few months now. It allows players to get a better view of a room by turning on the lights, while at the same time having many of the room lights off by default to improve framerate. (Lights are expensive for large buildings containing a thousand rooms.)

I've added the ability for AI people in buildings to turns lights on and off as well. AIs will turn the light on as they enter a room, and turn it back off again when they exit if no one else is in the room. This only applies to people in buildings near the player to avoid unnecessary toggling of distant room lights.

I also added logic to query whether or not the player is in a lit room that takes into account shadow casters. I plan to use this at some point to allow the player to hide from enemies in the darkness. The system is mostly implemented, but I haven't enabled it yet.

Doors

The player can open and close interior room and closet doors with a key press. Exterior building doors automatically open and close to admit the player. I've added logic for the AI to open doors, which is controlled by a config file parameter. If the AI can't open doors, the path finding algorithm will attempt to navigate around closed doors if possible. I had to rewrite the door drawing code to allow doors to have different open vs. closed states on each floor of the building, rather than having a single door that extends down between all floors. The rewrite allows doors to be drawn sparsely based on player location and view direction, which was required to handle millions of doors across all buildings in the scene.

I added the concept of locked doors a few days ago. The user defines the probability of doors being closed and/or locked in the config file. Locked doors can only be opened after the player finds a key, which are hidden around the building in drawers. The same key can be used for every door of that building, but won't work on doors in another building. AI people have similar flags for whether or not they have keys and can open locked doors. If the player has a key but the AI doesn't, it's possible to lock the AI in a room. The key + locked doors system will be important for later gameplay.

Pickup Items

I added a player inventory and made almost every placed item something that can be picked up. There's an inventory weight limit, so some of the larger items such as the couch and refrigerator are too heavy to pick up and carry. But the player can pick up most smaller furniture, fixtures, appliances, items on tables, etc. This includes fun things like toilets, sinks, stoves, nightstands, rugs, pictures, potted plants, TVs, chairs, ceiling lights, exit signs, men's/women's restroom signs, etc. Every item has a weight and a monetary value, and some items have special effects. The player's goal is to steal the maximum value of items and make it out of the building alive with their loot. Heavy items will slow the player down while they're being carried.

Some objects must be picked up in multiple parts. For example:

  • Beds: take pillows, then sheets, then mattress; bed frame is too heavy to pick up
  • Potted plants: take plant, then soil, then pot
  • Pictures: take picture, then frame
  • Tables: must take everything off the table before the table itself can be picked up
  • Wine Racks: must individually remove every bottle of wine before taking the wine rack

Bottles function as power-ups/special effects, depending on what type of drink they are. Empty bottles have no effect. Coke and water heal the player. Beer and wine make the player drunk, which enables some neat scree space effects like drunken wave, double vision, and blurry vision. [I would like to thank my daughter Kate for input on these effects!] This will all be important for later gameplay. I plan to add other drinks such as poisons that hurt the player in some way (damage, blindness, slow speed, etc.)

I had some difficulty handling objects on shelves and in closets because they're not actual C++ objects stored with the building. They're only drawn as part of the shelves and closets when they're visible to the player, so they're all temporaries created in the drawing code. It took quite a bit of work to allow the player to pick these objects up, and to have the system remember what was taken if the player walked away and came back later. I didn't want to allow the player to pick up a valuable item from the same shelf or closet more than once, even if they walked to the other side of the map and back. What I did was to "expand" these storage containers into real objects when the player attempted to use the "pick up" key on them so that they can be properly handled. This required quite a bit of code reorganization. It also has some runtime cost because expanding an object requires rebuilding the vertex data for the entire room detail geometry of that building.

Look at all these great items in here for me to steal. Unfortunately, I don't have the carrying capacity to take them all, and this guy isn't happy to see me here.

Drawers

I need a way to distract players from zombies so that they're caught off guard. What better way than encouraging players to spend time searching through desk, dresser, and nightstand drawers for keys and other valuables. Each drawer can be individually clicked on to open and close, and can contain a single item. The player can decide to pick up the item to add to their inventory. Some drawers are empty, some contain boxes, and on rare occasions a drawer contains a key. I plan to eventually add other items to drawers such as bottles, books, papers, pens, pencils, cell phones, wallets, and money. At some point I may also allow the player to open kitchen cabinet doors.

The room key can be found in a dresser, desk, or nightstand drawer. Other drawers are empty or contain boxes.

Dynamic Items

Okay, the player can now pick items up. What about dropping them? Simple spheres are the easiest type of shape for implementing collision detection and physics. I started by adding soccer balls and basketballs to some bedrooms. These can be picked up, carried around by the player, and dropped. I later decided that it was more fun for the player to throw balls rather than dropping them. The player can also kick them while on the floor, or in mid-air, if they get close enough. AI people walking around the building will also kick any balls they happen to run into.

I've implemented proper collision detection and physics for balls, including gravity, momentum, static and kinetic friction, and elasticity. Most of this was adapted from my other/existing gameplay framework, though it's all new code. Balls will roll around on the floor (including proper texture rotation), bounce off of room objects, bounce down the stairs, and even roll under beds and possibly get stuck. They cast and receive dynamic shadows from room lights.

Balls contribute to gameplay by emitting sound which alerts zombies. They can either be helpful when thrown as a distraction/diversion, or harmful when the player accidentally kicks one. I've scattered them around in the middle of floors to maximize the chance of the player accidentally running into a ball.

Soccer balls and basketballs can be picked up, kicked, and thrown by the player. The basketball has rolled under the bed.

Sounds

I've added lots of new sounds for building gameplay mode. Everything discussed here has sound: switching on and off lights (clicks), opening and closing doors and drawers, picking up objects, throwing and kicking balls, bouncing of balls, drinking from bottles, and even walking on the floor. I've included damage sound effects for the player and various zombie moans for people in buildings.

Sound is important for gameplay. Zombies can't see through walls, but they can hear noise made by the player. Louder or repetitive sounds can be heard from further distances and are more effective at attracting zombies from other parts of the building. It's important for the player to try to be as quiet as possible while searching the house for valuables.

Another strategy is to make a lot of noise in one part of a house to attract zombies, then sneak to the other end of the house to do your searching. Or you can place some balls near a doorway and hope a zombie runs into them, making noise and attracting other zombies (away from you). If you're feeling bold you can close some doors so that zombies must open them to enter rooms. This can either be used to distract other zombies, or alert you to a nearby zombie entering the room that you're in while you're searching. If you have a key you can even lock a zombie out of the room, assuming it doesn't have a key.