2
\$\begingroup\$

Hello im a total noob so please dont blame me. So, I have this code but I cant find a fitting answer on how to check if everything tagged "Target1" is destroyed. Most of the answers are either overcomplicated or ,and most certainly, im too stupid

public Transform teleportTarget;
public GameObject thePlayer;
public Transform[] spawnLocations;
public GameObject[] whatToSpawnPrefab;
public GameObject[] whatToSpawnClone;

void spawnTargets()
{
    whatToSpawnClone[0] = Instantiate(whatToSpawnPrefab[0], spawnLocations[0].transform.position, Quaternion.Euler(0, 180, 0)) as GameObject;
    whatToSpawnClone[1] = Instantiate(whatToSpawnPrefab[1], spawnLocations[1].transform.position, Quaternion.Euler(0, 180, 0)) as GameObject;
    whatToSpawnClone[2] = Instantiate(whatToSpawnPrefab[2], spawnLocations[2].transform.position, Quaternion.Euler(0, 180, 0)) as GameObject;
    whatToSpawnClone[3] = Instantiate(whatToSpawnPrefab[3], spawnLocations[3].transform.position, Quaternion.Euler(0, 180, 0)) as GameObject;
}

private void TeleportPlayer()
{
    thePlayer.transform.position = teleportTarget.transform.position;
}

Im just looking for a way to check if all GameObjects Tagged "Target1" (in the whole game) are destroyed and then to spawnTargets and TeleportPlayer. Previously I had the bug, that when they respawned it wasnt checking anymore. It has to check all the time.Because else I get stuck, because teleport teleports me all the time. I hope you understand what I mean

I know this is a easy question but im a noob and im sorry for wasting your time, still I hope you can help me.

\$\endgroup\$
2
  • \$\begingroup\$ You could check if the array's length returned by FindActorsWithTag (docs.unity3d.com/ScriptReference/…) is 0. Altough it does not say whether they are destroyed, you can deduce that if they are none it is because they were destroyed. \$\endgroup\$ Jun 4, 2019 at 19:34
  • 1
    \$\begingroup\$ Did you try implementing the answers to this related question? Where specifically did you run into trouble? \$\endgroup\$
    – DMGregory
    Jun 4, 2019 at 20:00

3 Answers 3

2
\$\begingroup\$

I want to check if all GameObjects tagged "Target1" have been destroyed, call a function like what you want for example instantiate something and etc...

here is code that you want:

void Update(){
    if(GameObject.FindGameObjectsWithTag("Target1").Length <= 0)
        //call your function to spawn targets and teleports
}
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Two considerations here: 1) searching every object in the scene to gather the ones with the right tag, and allocating a new array to return them in, is slightly expensive. Doing this every frame in Update is an unnecessary cost. 2) Do you expect that the return value could ever have a length less than zero? The code seems to anticipate this, which may cause confusion since arrays have only non-negative lengths. \$\endgroup\$
    – DMGregory
    Jun 5, 2019 at 11:44
  • 2
    \$\begingroup\$ @DMGregory while I agree with most of what you said, it should be noted that FindGameObjectsWithTag doesn’t actually search through every object. In particular it does not look through objects that are untagged. Not that that’s a good reason to use this method. \$\endgroup\$
    – Ed Marty
    Jun 5, 2019 at 13:30
  • \$\begingroup\$ Thanks for the clarification Ed! Out of algorithmic habit, I'm looking at the big-O style worst case, in which every scene object has a tag. So the upper bound for the search is the entire scene, even if the value in practice can be lower. ;) \$\endgroup\$
    – DMGregory
    Jun 5, 2019 at 13:47
3
\$\begingroup\$

I'd recommend not using tags for this, as searching for matching tags is an unnecessary cost.

Instead, as I described in this related question, I'd recommend creating a MonoBehaviour that marks the objects you want to count, something like this:

public class CountedObject : MonoBehaviour {

    public static int count { get; private set; }

    public static event System.Action AllObjectsDestroyed;

    void Start () {
        // Count every object as it's initialized.
        count++;
    }

    void OnDestroy () {
        // Decrement the count when objects are destroyed,
        // and optionally fire an event when the last one is gone.
        if (--count == 0 && AllObjectsDestroyed != null)
            AllObjectsDestroyed();
    }
}

The static int count variable is shared among all the marked objects. Every time one enters the scene with Start() it increases, and every time one is Destroy()ed, it decreases.

The only time you ever need to check if all objects have been destroyed is when actually processing the destruction - we don't need a script checking for it every frame in Update.

Another script that's interested in getting called when the last object has been destroyed can subscribe to the event, like so:

CountedObject.AllObjectsDestroyed += OnAllDestroyed;

Where void OnAllDestroyed() { ... } is the function you want to call once the last object is gone.

If you want to track/display a count, you can access it with no searching or extra computation or memory allocations, just by asking for:

CountedObject.count
\$\endgroup\$
1
\$\begingroup\$

You already seem to keep an array of objects you spawned from the script in whatToSpawnClone. So you can use that array to check how many of them are still alive. You can check if a game object is destroyed by comparing it to null. GameObject has a special overload for the ==-operator which which returns true when you compare a destroyed object to null.

Here is a method you can add to the behaviour which contains the code snippet from the question which checks if all the spawned objects are destroyed.

private bool AtLeastOneCloneAlive() {
     foreach(GameObject o in whatToSpawnClone) {
         if (o != null) return true;
     }
     return false;
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .