How shall I change a variable in multiple copies of a prefab?

I have a prefab of a box, called box, and i want to get all 5 of them and change a variable within their script. Right now i have it find one of the boxes every cycle and change it but it didn’t work.

using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;

public class CameraFollow : MonoBehaviour
{
    [SerializeField] Transform car;
    private Camera mainCamera;
    private bool inMap = false;
    public Van van;
    public GameObject Box;
    void Start()
    {
        mainCamera = Camera.main;
    }
    void LateUpdate()
    {
        Box = (GameObject)FindObjectOfType(typeof(Boxer));
        if (Input.GetKey(KeyCode.D) && transform.position.x < 20)
        {
            transform.position = new Vector3(transform.position.x + 25 * Time.unscaledDeltaTime, transform.position.y, -10);
        }
        if (Input.GetKey(KeyCode.W) && transform.position.y < 35)
        {
            transform.position = new Vector3(transform.position.x, transform.position.y + 25 * Time.unscaledDeltaTime, -10);
        }
        if (Input.GetKey(KeyCode.A) && transform.position.x > -20)
        {
            transform.position = new Vector3(transform.position.x - 25 * Time.unscaledDeltaTime, transform.position.y, -10);
        }
        if (Input.GetKey(KeyCode.S) && transform.position.y > -35)
        {
            transform.position = new Vector3(transform.position.x, transform.position.y - 25 * Time.unscaledDeltaTime, -10);
        }
        if (Input.GetKeyDown(KeyCode.M))
        {
            if (!inMap)
            {
                mainCamera.orthographicSize += 10;
                inMap = true;
                Time.timeScale = 0;
            }
            else
            {
                mainCamera.orthographicSize -= 10;
                inMap = false;
                transform.position = new Vector3(car.position.x, car.position.y, -10);
                Time.timeScale = 1;
            }
        }
        if (!inMap)
        {
            transform.position = new Vector3(car.position.x, car.position.y, -10);
            van.inMap = false;
            Box.GetComponent<Boxer>().inMap = false;
        }
        else
        {
            van.inMap = true;
            // the area i want to change the variable
            Box.GetComponent<Boxer>().inMap = true;
        }
        Debug.Log(inMap);
    }
}

FindObjectOfType will only find the first object in the hierarchy and ignore all others, so no matter how many times you call it, it will just keep returning the same object. You can use FindObjectsOfType instead, which will return an array, and then you can iterate through the array.

Mind you, using these methods is not ideal as all existing game objects will need to be iterated each time they are called. It’s much better to have a list that stores all active boxes and just iterate through that each time you need to.

1 Like

Drag them into an array, iterate the array and do whatever you want to do to them.

If they are created at runtime, then add them to an array (or List()) as you are creating them so you know where they are.

Keep in mind that using GetComponent() and its kin (in Children, in Parent, plural, etc) to try and tease out Components at runtime is definitely deep into super-duper-uber-crazy-Ninja advanced stuff.

Don’t use all those Get/Find things unless you absolutely MUST use them. And when you do decide you’re ready to do it, here’s the bare minimum of stuff you absolutely MUST keep track of if you insist on using these crazy Ninja methods:

  • what you’re looking for:
    → one particular thing?
    → many things?
  • where it might be located (what GameObject?)
  • where the Get/Find command will look:
    → on one GameObject? Which one? Do you have a reference to it?
    → on every GameObject?
    → on a subset of GameObjects?
  • what criteria must be met for something to be found (enabled, named, etc.)
  • if your code expects one instance and later you have many (intentional or accidental), does it handle it?

If you are missing knowledge about even ONE of the things above, your call is likely to FAIL.

If you have issues, start debugging. We know the above methods will ALWAYS work so find out what you’re doing wrong before bothering to make a forum post.

This sort of coding is to be avoided at all costs unless you know exactly what you are doing.

Botched attempts at using Get- and Find- are responsible for more crashes than useful code, IMNSHO.

If you run into an issue with any of these calls, start with the documentation to understand why.

There is a clear set of extremely-well-defined conditions required for each of these calls to work, as well as definitions of what will and will not be returned.

In the case of collections of Components, the order will NEVER be guaranteed, even if you happen to notice it is always in a particular order on your machine.

It is ALWAYS better to go The Unity Way™ and make dedicated public fields and drag in the references you want.

1 Like

You’re probably right, but i have no idea how to implement this. Could you help me?

I will make the guess that you can figure this out. Particularly if you look at the individual issues and not as a single case of trying to move a box.

I’m not sure “super-duper-uber-crazy…” is a phrase I would use when explaining concepts. Kurt, all the non-essential wording is likely to confuse a novice.

As you type LateUpdate() you should “feel” that you need to be aware of what code goes inside. This is called repeatedly so any waste is compounded.

Note a few things. You assign the Box GameObject to a property. It doesn’t need to be a property if you constantly overwrite it and (as mentioned) if you locate it once (or assign it in the editor) you shouldn’t need to keep looking for it.

Note also that you don’t really want the GameObject. You are using the Boxer object not the Box GameObject. You get that in 2 places inside the method, again using GetComponent. These references aren’t changing so assign them and know they have been set and can be used from then one.

And note your Debug.Log() within the method. Again you can do it but you need to feel uneasy because “I’m putting a debugging statement” in something that repeats often and quickly. The log will get cluttered and if you write it to a file, the file will get big, very fast.

Take some time out to examine a List and/or Array-based solution. See if you can assign the boxes to the collection in the Inspector. The time spent will benefit you as new issues arise.

2 Likes

public GameObject[] Boxes;

drag them into the Inspector slots after you set the size of the array (also in the Inspector).

In code, reference them using Boxes[0], Boxes[1], etc. Use a loop to do something to all of them as needed.
It’s exactly like any other array, but it holds GameObjects.
Also as mentioned: you’re actually looking for the Boxer component. So the array could be that instead, unless you need to access anything else on those GameObjects.