Search object in scene

Hi everybody,

I’m trying to make a simple script that allows me to find and mark an object with a specific TAG in the scene.

I made a UI where I can type a text and then, by pushing a simple button, the system colors all the objects in the scene which have the same TAG as the text written.
My problem is that if I then want to search another TAG in the scene and color all the objects with that TAG I cannot undo the previous search and I finish up with all object with both TAG searched colored.

I upload my simple code that marks the objects.

ObjectFinder2.zip (476 Bytes)

Can anyone help me to fix this issue? I want to clear the first search so that I have just one TAG searched at the time.

Thanks in advance
Regards

Fabio

Hi Fabio,

Could you please paste your current code here and format it? Alternatively, paste it on pastebin.com and share a link.

What do you mean by undo the previous search? What is supposed to happen?

Hello Nina,

here is my code:

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class ObjectFinder3 : MonoBehaviour {

    public InputField typedTAG;

    [SerializeField] GameObject[] foundObject;

    private Renderer rend;
    public Material material;
    private Material[] listaMateriali;

    public void findObject()
    {
        foundObject = GameObject.FindGameObjectsWithTag(typedTAG.text);

        foreach (GameObject objectWithTAG in foundObject)
        {
            rend = objectWithTAG.GetComponent<Renderer>();
            int numeroMateriali = rend.materials.Length;
            listaMateriali = Enumerable.Repeat(material, numeroMateriali).ToArray();
            rend.sharedMaterials = listaMateriali;

        }        
    }
}
 
}

The main idea is that I have a few objects in a scene with different TAG. Then, by using an UI I type some text in an InputField and by clicking on a button I call for the findObject method which changes the material of all the objects with a TAG equal to the typed text.

The step I want to add is to have a new method (and call it through another button in the UI) which restores the original color.
In this way if I call again for the findObject method I end up with all the objects of the last typed TAG with a different material.

Can you help me with this step I want to add?

Thanks for your help

Regards

Fabio

Thank you.

Here is the problem: Your computer does not remember anything unless you explicitely instruct it to do that. There is no concept of “previous”, though. To make your computer remember something, you need to cache the information in a variable. If the variable is supposed to persist for the lifetime of your current instance, make it an instance variable.

For example:

[SerializeField] Material newMaterial; // the new material you assign

private Material originalMaterial;  // the original material of the object

void ChangeMaterial()
{
   GameObject go = FindGameObjectWithTag("SomeTag");
   Renderer renderer = go.GetComponent<Renderer>();
   originalMaterial = renderer.material;
   renderer.material = newMaterial;
}

void SetMaterialBackToOriginal()
{
   GameObject go = FindGameObjectWithTag("SomeTag");
   Renderer renderer = go.GetComponent<Renderer>();
   renderer.material = originalMaterial;
}

This is an example to show you the idea, not the solution. It is better to cache the found object(s) like you did. Call SetMaterialBackToOriginal() before you look for objects with another tag.

Hopefully, this helps. :slight_smile:

Hi Nina!

it works, thank you.
I then tried to make this with multiple objects but I came up with an error.
I write here below my script adn the error:

public Text label;
[SerializeField] Material newMaterial; // the new material you assign

private GameObject[] go;
private Material[] originalMaterial;  // the original material of the objects

private int i;

public void ChangeMaterial()
{
    go = GameObject.FindGameObjectsWithTag(label.text);

    for (i = 0; i < go.Length; i++)
    {
        Renderer renderer = go[i].GetComponent<Renderer>();
        originalMaterial[i] = renderer.material;
        renderer.material = newMaterial;
    }
}

public void SetMaterialBackToOriginal()
{
    for (i = 0; i < go.Length; i++)
    {
        Renderer renderer = go[i].GetComponent<Renderer>();
        renderer.material = originalMaterial[i];
    }
}

may you help me to understand this issue please?

thank you
regards

Fabio

NullReferenceException means that a reference (“link”) to an instance is missing. Double click on the error message to see to which line in your code it is referring.

Log the values of the relevant variables into your console to see which one is null.

Hi Nina,

it says that the error is here:

but I don’t get the point. Am I missing something with the correct index i?

Thank you Nina

Fabio

If there was an issue with the index, you’d get an IndexOutOfRangeException.

Make sure that originalMaterial and renderer are not null. It seems as though the Material array has not been initialised.

originalMaterial = new Material[go.length];

Hi Nina, thank you so much. It works!
Can you please tell me more about the “new” term? Why it is not sufficient to just declare the variable, but I need to instantiate it? Can you tell me when I need to instantiate a variable?

I report here belox my code. Maybe it helps someone:

private enum State { AllowSearch, DenySearch };
private State state = State.AllowSearch;

public Text label;
[SerializeField] Material newMaterial; // the new material you assign

private GameObject[] go;
private Material[] originalMaterial;  // the original material of the objects

private int i;

public void ChangeMaterial()
{
    if (state == State.AllowSearch)
    {
        state = State.DenySearch;
        go = GameObject.FindGameObjectsWithTag(label.text);
        originalMaterial = new Material[go.Length];

        for (i = 0; i < go.Length; i++)
        {
            Renderer renderer = go[i].GetComponent<Renderer>();
            originalMaterial[i] = renderer.material;
            renderer.material = newMaterial;
        }
    }
    else
    {
        return;
    }
}

public void SetMaterialBackToOriginal()
{
    if (state == State.DenySearch)
    {
        state = State.AllowSearch;

        for (i = 0; i < go.Length; i++)
        {
            Renderer renderer = go[i].GetComponent<Renderer>();
            renderer.material = originalMaterial[i];
        }
    }
    else
    {
        return;
    }
}

I added a Game state variable that allows and denies to search objects in the scene.

Thanks again Nina
Regards

Fabio

Well done, Fabio! I’m glad it’s working now. :slight_smile:

Arrays are reference types. Their default value is null. With the new keyword, you create a new object. If you want to learn more about the difference between value types and reference types as well as memory usage and garbage collection, please refer to this doc.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.