Friends, food, and flourishing

Modeling enemies with nested game objects in Unity

A post to help me think about enemies in Toni is Our Only Hope, a Nobody Listens to Paula Poundstone fan game. I’m a big fan.


I want viruses like this:


There are two main game objects (GOs), from different asset libraries. There’s the main virus, the blue thing. There’s its eye, showing where the virus is facing, for detecting the player. It’s a beholder from D&D lore.

Both are animated. The virus floats up and down (on the Y axis) and rotates on Y, until it detects the player. Then it stops movement on Y, and chases the player.

The eye has three animations. When the player is not detected, it loops through a lazy idle animation. When the player is detected, there is one iteration of an I-see-you animation. Then it loops an I’m-after-you animation.

(There are three other virus types that have the same structure and goals, using different base models.)


The virus attacks when the player is detected on a sphere ray extending 15m on the eye’s Z axis. It uses a navmesh, to go around obstacles.

Most obstacles are static level geometry, apart from four types.

  • Other viruses that should jostle each other.
  • Cats (the player is trying to rescue them). The visues should not move cats, but go around them.
  • Pickups for the player. The viruses should go around them, not move them.
  • The player. The virus should shrink and be absorbed when reaching the player.

The player gathers cats by running into them. Pickups are optional. An interact message appears when the player gets close.

The eyes have it

Recall the virus rotates towards the player, charging once the eye detects the player. The eye keeps facing the player as it moves. So the eye is the thing most likely to hit the player. It’s not certain, if the player is dodging fast. In that case, the edge of the virus might hit the player before the eye has rotated to face the player. Still, the eye is the most likely thing to hit the player.

Different volumes for different things?

There are different volmes for different purposes:

  • Navigation volume. The height and radius Unity’s AI system should use when baking navigation areas.
  • The space-occupied volume. Used to determine how the virus moves when it jostles against other objects.
  • Hit-the-player volume. When this volume intersects with the player, the player is hit by the virus.

The viruses move up and down in place. (They might also wander around in the future, but I haven’t programmed that yet.) For navigation purposes, each virus’s volume should cover the full range of its motion, from the top of the virus at the top of its movement arc, to the bottom of the virus at the bottom of its arc. I’m not sure about this, but it seems safest, if I don’t want viruses to get stuck when moving around.

The radius of the nav volume should be big enough to include both the virus and the eye, but no larger. Too large, and viruses won’t follow attack routes they should. Again, I’m not sure about this.

The space-occupied volume should be modeled by a compound collider, one for the main virus, and one for the beholder. Each one should fit its corresponding element closely. The compound collider should not encompass the up-and-down movement areas, though the colliders themselves should move up and down during the animation, along with the GOs they’re tied to. I’m not sure this is best, but it seems reasonable.

The hit-the-player volume should be the largest, encompassing all the others, and a little bit extra. Say it was too small, so the space-occupied volume of the eye poked out of the hit-the-player volume. The virus might come up to the player, then stop without attacking, since the eye’s collider would prevent the hit-the-player collision from happening.

There might be a collision detection issue here. If GOs are moving fast compared to the frame rate, the hit-the-player collision might happen between frames and be missed, while the hit-the-player collision happens. I might have to use continuous collision detection.

There might be a playability issue, too. Since the hit-the-player volume is larger than the way the virus looks on screen, players might shout, ‘No fair! It didn’t get me!” To counter that, maybe I can add something non-solid sticking outside of the hit-the-player volume, like a particle effect, or a ranging laser. That would look pretty cool. Unless you have other suggestions?

Prefab structure

Like so:

Prefab structure

The beholder has the eye stuff, and two colliders, a regular (nontrigger) collider for space the eye occupies, and a trigger collider that’s slightly larger for detecting hit-the-player. (They could both be sphere colliders if one is on a child object.)

The eye would also have the non-solid range extender thing, like a particle effect or ranging laser. It would have an animator as well, with a parameter for switching animations.

Blue_Bac_Mesh has the render stuff for the main virus, and two colliders, a regular one for space occupied, and a triggery one for hitting the player. It would have an animator for moving up and down. It could rotate the virus too, or that could be done separately.

The top level would  have a NavMeshAgent with dimensions of the virus for navigation purposes. There could be an AudioSource, so the virus can screech when it detects the player.

There’s a controlling C# script, for watching for the player, and chasing it down. You could put it on the eye, if you want it to act as the “brain” of the virus. I put it at the top level, but it doesn’t matter, AFAIK.

I used the RaySensor component from the SensorToolkit to make the player detection code easier. It’s not essential, however. I have the old version of the asset, though a new one is available.

That’s all, folks

Let me know if you have any suggestions.

Leave a Reply

Your email address will not be published. Required fields are marked *