Finding nearest object in range by tag and changing it's color

Hey everyone!

I tried for 2 days to solve my problem and finally gave up on trying this on my own.

Here’s what i want my script to do:

  • Find Objects with a certain tag, within a certain range (working)
  • Find the “nearest” of those objects (working)
  • Set the shader color to yellow for closest object within range (kinda working)
  • Set the shader color to green for everything else (kinda working)

The Problem:
When my object was, but is no longer in range, i can’t figure out, how to change it’s color back to green.
When no object should be in range anymore, the “last-to-be-closest”-object stays yellow.

My Code:

void changeColor() {
                GameObject closestEnemy = FindClosestEnemy();
                transform.position = closestEnemy.transform.position;
                float distance = lockDistance;
                Vector3 position = PlayerObj.transform.position;

                GameObject[] gos;
                gos = GameObject.FindGameObjectsWithTag("camTarget");
                foreach (GameObject go in gos) {
                    Vector3 diff = go.transform.position - position;
                    float curDistance = diff.sqrMagnitude;
                    if (curDistance < distance)  {
                        if (go == closestEnemy) go.GetComponentInChildren<Renderer>().material.SetColor("_BaseColor", Color.yellow);
                        if (go != closestEnemy) {
                            go.GetComponentInChildren<Renderer>().material.SetColor("_BaseColor", Color.green);
                        }                   
                        distance = curDistance;
                    } else {
                        go.GetComponentInChildren<Renderer>().material.SetColor("_BaseColor", Color.green);
                    }
                }
            }

public GameObject FindClosestEnemy()
    {
        GameObject[] gos;
        gos = GameObject.FindGameObjectsWithTag("camTarget");
        GameObject closest = null;
        float distance = lockDistance;
        Vector3 position = PlayerObj.transform.position;
        foreach (GameObject go in gos)
        {
            Vector3 diff = go.transform.position - position;
            float curDistance = diff.sqrMagnitude;           
            if (curDistance < distance)
            {               
                closest = go;
                distance = curDistance;
            }
        }
        return closest;
    }

I really hope someone can help me out. I just can’t get my head around it anymore.

PS.: I know, “FindGameObjectsWithTag” is expensive. It’s not called every frame.

You are looking at your problem as:

  • Find all objects in range
  • Set the closest one to yellow
  • Set the rest to green
  • Also, if an object goes out of range, set it to green

It sounds to me like you can make things much easier if you instead look at it like this:

  • Find ALL objects, REGARDLESS of range
  • Set the closest one to yellow
  • Set the rest to green

If for some reason you can’t do that, then I recommend you store the closest one in a variable when you change its color to yellow, and then the next time your code runs it should change the object in that variable to green before overwriting it with the new closest.

1 Like

First of all: Thanks for your reply.

Sadly, this is what i already can do:

  • Find ALL objects, REGARDLESS of range
  • Set the closest one to yellow
  • Set the rest to green

If i use Mathf.Infinity for the Range it does check everything yeah, but i need to define a range somewhere for when it is out-of-range - and if nothing is in range, set everything back to green (even if it was yellow / in range before).
And that’s the part i can’t wrap my head around right now.

EDIT: Nvm, this part helped me a ton:

My changeColor function looks like this now:

void changeColor() {
                if (stored!= null) stored.GetComponentInChildren<Renderer>().material.SetColor("_BaseColor", Color.green);
                GameObject closestEnemy = FindClosestEnemy();
                transform.position = closestEnemy.transform.position;
                float distance = lockDistance;
                Vector3 position = PlayerObj.transform.position;

                GameObject[] gos;
                gos = GameObject.FindGameObjectsWithTag("camTarget");
                foreach (GameObject go in gos) {
                    Vector3 diff = go.transform.position - position;
                    float curDistance = diff.sqrMagnitude;
                    if (curDistance < distance)  {
                        if (go == closestEnemy) {
                            go.GetComponentInChildren<Renderer>().material.SetColor("_BaseColor", Color.yellow);
                            stored = go;
                        }
                        if (go != closestEnemy) {
                            go.GetComponentInChildren<Renderer>().material.SetColor("_BaseColor", Color.green);
                        }                   
                        distance = curDistance;
                    } else {
                        go.GetComponentInChildren<Renderer>().material.SetColor("_BaseColor", Color.green);
                    }
                }
            }

That’s the little push in the right in needed right there. Thanks a ton. I owe you :slight_smile:

  • Find all objects regardless of range
  • Calculate which one is closest
  • Test if the range of the closest object is above or below your threshold
  • If it’s within the threshold, make it yellow; otherwise make it green
  • Make everything else green

I might look at it this way

  • Find all objects
  • Set each object to green, while checking distance and keeping track of which object is the closest
  • If the closest object is within range, set it to yellow

This would result in you setting the color of the closest object twice, but you’d only need to loop through the list of objects once and it would be pretty straight forward to implement.