Getting nearest object with tag

I copied a video tutorial on how to make a ai that patrols, chases the player, than attacks. I am making a simulation where creatures go around and am using the script to make them eat plants. I currently have it where

Plant = FindGameObject(“plant”).transform;

But this was for when there is only one player. Since i will need several tags i need to set the plant to be the closest object with the plant tag instead. How do i do this

Not sure which method you’re referring to in your code since ‘FindGameObject’ isn’t a method. Do you mean ‘GameObject.Find’? But that doesn’t find by tag, that finds by name.

There is also GameObject.FindWithTag:

But that only returns the first one it finds. If you want to find any of them with a tag, then you’re going to have to first get all the GameObjects with the tag via FindGameObjectsWithTag:

Then you loop over it and you check the distance from some position and take the nearest.

var arr = GameObject.FindGameObjectsWithTag("plant");
var pos = transform.position; //assuming this code is running on the gameobject you want to find closet to

float dist = float.PositiveInfinity;
GameObject nearest = null;
foreach(var go in arr)
{
    var d = (go.transform.position - pos).sqrMagnitude; //use sqr magnitude as its faster
    if (d < dist)
    {
        nearest = go;
        dist = d;
    }
}

//nearest if not null is the nearest gameobject. If null no gameobject was found

Of course this all is a very naive approach to the task you’re attempting to accomplish. Using tags and FindGameObjectsWithTag is slow and creates a lot of garbage. Usually you would cache a collection of all available targets and then just access that collection. Instead of querying all of them every time you want to test.

A simple way of doing this is just have a Plant class attached to all Plants and on start add it to the collection, and on destroy remove it.

public class PlantComponent : MonoBehaviour
{

    public static readonly HashSet<PlantComponent> AllPlants = new HashSet<PlantComponent>();

    void Start()
    {
        AllPlants.Add(this);
    }

    void OnDestroy()
    {
        AllPlants.Remove(this);
    }
}

Heck you could even streamline the above loop with some linq (though yes linq does create a little garbage… just negligible).

var pos = transform.position;
var nearest = PlantComponent.AllPlants.OrderBy(go => (go.transform.position - pos).sqrMagnitude).FirstOrDefault();

Though really, the foreach loop from before is faster than this. The orderby will create a delegate and other garbage, and it’ll do a full sort which scales non-linearly the more plants there are… where as the for loop is a simple O(N) query. But I figured I’d just show you another example just to demonstrate there’s always more than 1 way to skin a cat.

2 Likes

Running that every frame for every creature may negatively impact your performance.

One of the best ways is to run something in Start() to find all the plants.

You can do that by name, like you do above, but you need a little function that will return all the matching GameObjects.

You could also make a blank MonoBehavior “plant marker” script and then use FindObjectsOfType() and it will give you an array.

Once you have the array, you can iterate and find the closest one, using Vector3.Distance() to calculate.

Am having trouble understanding because am still kind of new but i think i kind of understand but is this code JavaScript because i use c# and i don’t know too much about java

Also when i tell the code to do something with nearest an error says nearest does not exist in this context. Such as

agent.SetDestination(nearest);

Or

Transform.LookAt(nearest);

Nope, I posted C#.

I’d have to see your actual code to know what exactly you’re referring to.

Transform.LookAt takes in a Transform, nearest in my example above is a GameObject and a PlantComponent in another.

SetDestination may be NavMeshAgent.SetDestination, which takes in a Vector3.

How about you show us your script in its full, making sure to format it correctly with code tags:
https://discussions.unity.com/t/481379

Then maybe we can give you more specific help relative to your specific code as it appears you’re still rather new to C# in general and are having a hard time just understanding scope, data types, or even the syntax of C#.

I fixed it. All I had to do is put nearest = go.transform