Ways to do NPC detection and interaction?

I’m still very new to Unity, so forgive me if this is either something very obvious or something I shouldn’t be attempting at my level of knowledge, but I’m really interested in simulating ecosystems in Unity. I really enjoyed watching Sebastian Lague’s Coding Adventure where he created an ecosystem of Foxes, Rabbits and Plants

).

I’d like to try to do a similar project, but with a slight expansion. I’d like to create an ecosystem with a “Food Chain” consisting of something like Bears, Wolves, Foxes, Rabbits and Plants.

Where for example:

Rabbits eat Plants
Foxes eat Rabbits
Wolves eat Rabbits and Foxes
Bears eat Plants, Foxes and Wolves

To accomplish this, I’d like to write a script that basically does the following:

  1. Gives the Character the script is applied to the senses of Sight (Some Field of View angle in front of the character) and Hearing (A sphere around the character).
  2. Determine if another GameObject that can be interacted with has been detected by these senses.
  3. If a GameObject is detected, determine if the GameObject is food or a predator relative to the Character.
  4. If the GameObject is food, move toward it.
  5. Else if the GameObject is a predator, run away from it.

That way I can have various types of animals run toward their respective food and away from their respective predators.

The problem I’m having is that I don’t know how I should go about doing Steps 2 and 3 in this script. I’ve seen a few tutorials on how to do sight and hearing based detection scripts, but they seem to generally be focused on a specific target (namely the player as both Brackeys in

and the Unity Stealth Game Tutorial in

did by selecting a certain GameObject to trigger these senses) using NavMeshAgent and SetDestination. Ideally I’d like to have the script handle not only multiple copies of the same type of target (i.e. multiple foxes) but also multiple types (i.e. foxes and bears).

Could anyone point me in the right direction as to how I could have it detect more than one potential type of target and perform different behavior based on the type of target detected? Or if this is not possible as I’ve described, what would be the best way to work around it?

1 Like

You are actually completely on the right track I’d say, I think though because this is a big project you should break things down even further and do things very much one at a time, focus entirely on one mechanic unless of course one mechanic is reliant on the other. This is just an example as I don’t know what ideas you’re going for but just focus on doing purely the rabbits and the plants, then move onto the foxes going after rabbits depending on what order you’re doing them in.

I’ve actually built a simple village economy myself and I found when I broke things down and literally only focused on one particular mechanic I found it a lot simpler to implement. As for your question about finding targets, I recommend using the cone of vision to search for a gameobject tag, that should work fine and then what you can do is when the gameobject is within the field of vision you could perhaps have a boolean enabled and then have your code read off that.

I’ve frequently used booleans in my own project to help identify when my villagers have done something or not, this is a a pretty simple version of what you’re doing but I still had to work out how to dynamically search for gameobjects quite a bit.

Here my villager is going to the village store for food, in order to do this sort of thing you really need to study the ins and outs of not only finding gameobjects but getting gameobjects generally when you can’t use GameObject.FindGameObjectWithTag. One trick I used here is I actually had an empty which all my buildings are parented to and then the empty itself searches within the children for the gameobject I need in this case it’s the village store’s entrance. I use GetComponentInParent to reference the gameobject that the script is grabbing rather than having to deal with any nonsense that comes with using tags so that’s one option you could pick.

I bring this up because you need to do this with the cone of vision, one thing you could potentially do since you mentioned you were searching for stuff locally within the vision is you could make a list and then add any gameobjects within that list. You could then search for a specific tag depending on what you want the gameobject to look for and that will be a far more accurate and potentially cheaper way of looking for objects and having your agent interact with stuff but make sure to do this only within the list you’ve created as otherwise the script will simply search for any gameobject within the scene and that’s obviously not what you want.

Hope this helps you with your ideas, I think you’re on the right track and you just need to study more on how to use lists and how to search through the hierarchy.

Thank you for the encouragement and suggestions! Particularly your suggestion about creating a list based on the cone of vision and searching only that list. That is very insightful!

An Update:

I’ve been trying to get a simple hearing script to work using GameObject tags because that seems simpler than vision, but I haven’t gotten far at all. I created a simple scene with a Cube and a Sphere, both have rigidbodies and their respective colliders. The cube has two scripts, first a script that uses NavMeshAgent to move toward the sphere if it is within a certain distance (I have it set for 30 units), and this script works fine.

The second script is this one:

using UnityEngine;

public class HearingScript01 : MonoBehaviour
{
    void OnCollisionEnter(Collision other)
    {
        Debug.Log("Collision Detected");
        if (other.gameObject.CompareTag("Bear"))
        {
            Debug.Log("A Bear Detected");
        }
    }
}

I then added a Sphere Collider with a radius of 10 units to my Cube (In addition to the Box Collider it already had) and set it as a trigger. I also created a tag called Bear and tagged my Sphere as Bear.

Now, as soon as I hit run I get a “Collision Detected” in my Console, because it’s detecting my cube being in contact with the ground, I assume, but I don’t get an “A Bear Detected” message until they make physical contact.

My goal was to have the second script (HearingScript01) print “A Bear Detected” whenever the Sphere enters the large Sphere Collider around the cube. What have I done wrong?

Try OnTriggerEnter instead of OnCollision maybe?

1 Like

Thank you! That seems to be working as expected.

Just a heads up, If you set the GameObject to a trigger then from what I know you need to have OnTriggerEnter for it to work and then the opposite is true with OnCollision. It would have worked if you disabled OnTrigger in the inspector of course, disabling OnTrigger means the engine will treat your collider as a solid object.

Depending on how frequent your sounds are, it might be more efficient to have the source of the sound do collision detection instead. For example, if a bear steps on a twig, you could do an Physics.OverlapSphere check (centered on the twig) to get a list of all of the animals in the area and message them that a sound occurred that they might have been able to hear. That way you only need to do the collision check once when there’s a sound, rather then have each animal continually check for sounds at all times.