Thursday, August 18, 2022

Snakes in Buildings

So far I've added people, rats, and spiders to buildings. They can all be considered a sort of enemy of the player in gameplay mode. What other hostile animals can I add? How about poisonous snakes that attack the player when they get close.

Snakes are similar to rats because they stay on the floor and can't climb walls and other objects like spiders. Snakes are limited to the ground floor and currently can't be picked up by the player. They're more aggressive than rats, and will bite the player when in range rather than running and hiding under furniture. However, they completely ignore the player when the player isn't right next to them. This makes them easier to avoid, assuming you're paying attention to your surroundings and being careful when entering new rooms.

There are currently two types of snakes, those with rattles and those without. All snakes can damage the player by biting, but only rattlesnakes are poisonous and will do damage over time. This uses the same mechanic as spider bites. The only item that can cure the player of poison is the medicine bottle, which can be found in house medicine cabinets and on rare occasions in drawers. I modified the player inventory to allow medicine bottles to be collected and consumed later if not immediately needed, which make it a bit easier to survive snake and spider venom.

I used a similar approach to spiders when drawing snakes, forming them procedurally in code from transformed cylinders, cones, and spheres. They consist of 18 connected segments, representing individual ribs, with a head at one end and either a tail or a rattle at the other. I found two different textures to use for their scales, and added a random color variation from light brown to nearly black. Each snake has two eyes on the sides of its head and a forked tongue that will occasionally come out.

Four snakes on the kitchen floor. One is a rattlesnake. The center snake has its pink tongue out.

Snakes have a unique movement and animation system. Each segment moves individually in a smooth motion that follows the path of the segment in front. The head moves in a sine wave pattern to give the body movement a wavy, flowing path that I based on the movement of my pet snake Audrey and other images and videos of snakes I found online. Snakes can also curve or straighten their bodies to fit through narrow openings and avoid collisions.

Collision avoidance was by far the most difficult feature to implement. Snakes must avoid the following objects, ordered from highest to lowest priority:

  • The edges of the building bounding cube (otherwise bad things happen such as the code crashing or the snakes disappearing)
  • Exterior building walls (outside the building they're not drawn correctly)
  • Interior building walls
  • Open and closed doors
  • Stairs and elevators
  • Static room objects (furniture, appliances, etc.); fortunately I was able to reuse all of the rat collision logic for these.
  • Other snakes, rats, and spiders
  • Themselves; it's important to avoid self intersections; this one was quite challenging

I already had code for most of the items near the top of the list. The only real difference between snakes and rats related to static object collisions is that representing snakes as a bounding sphere is too inaccurate. For the purpose of detecting collisions for the snake itself, I only need to consider a bounding sphere around its head. The rest of the body will follow the path of the head and will also avoid the same static objects. However, checking for collisions with other snakes and the snake itself requires finding intersections with each cylindrical body segment.

It took quite some time to get all of this working. When a collision is detected, a new head direction is randomly chosen within the 180 degrees around the collision normal. Directions closer to the initial head orientation are given a higher weight so that snakes are more likely to continue along a similar path rather than reversing direction and doubling back on themselves. The most common modes of failure for collision detection resulted in the snake getting stuck with its head slightly inside a wall or other object (including its own body).

I was able to fix all but one case of the snake getting stuck with reasonable effort. The final case was where a snake was forced into a curve while colliding with another snake, and it spiraled into itself to the point where its head was completely surrounded by its body and it couldn't move. After several failed attempts, I finally fixed this by setting the collision normal to be the direction of the colliding segment coming from its head. This would force the head to turn toward the direction of the tail on collisions, rather than curving toward itself.

I also found and fixed a pretty funny bug. When the snake was stuck against an object such as the player, it would choose random new direction each frame. This would cause the head orientation to jiggle around randomly. In addition, this triggered the animation system to update, which resulted in the snake's eyes spinning around its head!

Here's a YouTube video showing a number of snakes in the living room of a house. They glide around on the floor and attempt to avoid objects, each other, and themselves. I find it quite interesting how they can weave between the table and chair legs using collision avoidance forces. Note that I already fixed the rat vs. snake collision bug. I was incorrectly using the snake's bounding sphere radius rather than the snake's body radius to move the rat to a non-colliding position.


2 comments:

  1. Seems like the next feature to add would be snakes eating rats! Or maybe allowing snakes and rats to climb over small objects?

    ReplyDelete
    Replies
    1. Haha! Yes, I think you're the third person to suggest snakes eating rats. I need to find a way to build it into gameplay. If snakes simply eat rats when they get near each other, then the rats will likely disappear before the player even notices them. I need to find a way to only have snakes eat rats when the player is watching. Maybe I can have snakes guarding areas, and the only way to make them leave is to feed them a rat? The player can pick up, carry, and drop rats already. It would be easy to manually set up this scenario, but more difficult to do with procedurally. Then there's the question of how to animate a snake eating a rat.

      The difficulty with rats climbing objects is the animation again. I can move their legs already, but I think I need to bend their bodies to make them climb. Where would I even get an animation for that? At least with spiders I only have to move their leg end points to make them appear to climb.

      Delete