FindGameObjects with tag adding an extra entry to the list.

Hi, I have spend the past couple of hours trying to figure out why, but for some reason this code adds one extra entry to the list of game objects. Any help would be appreciated!

EDIT: Just realized I forgot to mention this, yes I did break the look to see if it would actually clear the list, it did but when it goes back through to find the game objects it will add an extra missing game object to the list.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public int level = 1;
    public int spawnsLeft;
    public int totalEnemies;

    private int totalSpawners;

    private GameObject[] spawners;
    private List<GameObject> enemies;
    private GameObject[] bullets;
    private GameObject playerSpawn;
    private GameObject player;

    private void Start()
    {
        spawners = GameObject.FindGameObjectsWithTag("Spawner");
        totalSpawners = spawners.Length;
        playerSpawn = GameObject.FindGameObjectWithTag("PlayerSpawn");
        player = GameObject.FindGameObjectWithTag("Player");
        calcSpawns();
    }

    public void calcSpawns()
    {
        if (level > spawners.Length)
        {
            spawnsLeft = totalSpawners;
            spawnEnemies();
        }
        else
        {
            spawnsLeft = level;
            spawnEnemies();
        }
    }

    public void spawnEnemies()
    {
        while(spawnsLeft > 0)
        {
            int rand = Random.Range(0, totalSpawners);
            SpawnerScript activeSpawnerScript = spawners[rand].GetComponent<SpawnerScript>();
            activeSpawnerScript.spawnEnemy();
            spawnsLeft -= 1;
        }
        foreach(GameObject g in GameObject.FindGameObjectsWithTag("Enemy"))
        {
            enemies.Add(g);
        }
        totalEnemies = enemies.Count;
    }


    //Called from the projectile if the enemy is at <= 0 HP
    public void removeEnemy(GameObject enemy)
    {
        totalEnemies -= 1;;
        Destroy(enemy);
        checkIfAllEnemiesDead();
    }
    private void checkIfAllEnemiesDead()
    {
        if (totalEnemies <= 0)
        {
            nextLevel();
        }
    }

    private void nextLevel()
    {
        enemies.Clear();
        GameObject[] bullets = GameObject.FindGameObjectsWithTag("Enemy");
        foreach(GameObject g in bullets)
        {
            Destroy(g);
        }

        player.transform.position = playerSpawn.transform.position;
        level += 1;
        calcSpawns();
    }
}

I am not 100% sure what is going on with what you got, but I will say finding gameObjects with a tag isn’t the best to handle this situation (imo).


Two reasons: first finding with tag is incredibly slow, it has to crawl through the whole hierarchy to find what you are looking for and it uses a string. Second, it can be error bound. Imagine if someone accidentally adds a tag onto something it shouldn’t - its also hard to find them manually in the scene.


Having said that, this is where some sort of entity system comes in. When the game starts, gameObjects like spawners, enemies, and players will register themselves to the manager. Then you don’t have to worry about trying to find them.


Here is a very quick example of what I am talking about. Its a pretty straight forward registration - I personally do it very differently, but I didn’t want to go all into crazyness. This should work fine for what you are trying to do or give you ideas on how to handle it.


using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Place in scene somewhere to manage all entities
/// </summary>
public class EntityManager : MonoBehaviour
{
    // Simple singleton
    static EntityManager instance;
    public static EntityManager Instance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<EntityManager>();
            }

            return instance;
        }
    }


    List<Spawner> spawners;
    List<Enemy> enemies;


    public void RegisterEntity(Entity entity)
    {
        if (entity is Spawner)
        {
            if (spawners == null)
            {
                spawners = new List<Spawner>();
            }

            spawners.Add(entity as Spawner);
        }
        else if (entity is Enemy)
        {
            if (enemies == null)
            {
                enemies = new List<Enemy>();
            }

            enemies.Add(entity as Enemy);
        }

        Debug.Log(string.Format("{0} registered", entity));
        entity.WhoAmI();
    }

    // Create a method for unregistering - enemy might die or something (remove them from lists)
}


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Entity : MonoBehaviour
{
    protected virtual void Awake()
    {
        EntityManager.Instance.RegisterEntity(this);
    }


    public abstract void WhoAmI();
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// Place on your spawners
public class Spawner : Entity
{
    public override void WhoAmI()
    {
        Debug.Log("I am Spawner");
    }
}


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// Place on your enemies
public class Enemy : Entity
{
    public override void WhoAmI()
    {
        Debug.Log("I am Enemy");
    }
}


It looks rather complicated (maybe), but its actually pretty straightforward.
You have an EntityManager (which is a singleton) that contains all your entities that register to it. Then there is an Entity script. All the objects you want to keep track of should be an entity - all the things derive from it (which is why its abstract). By default, it will register itself to the entity manager. (Like I said, the registration is super dirty and quick, there are better ways).
Then there is two other scripts I made called Spawner and Enemy. Those derive from entity, and you slap those on the objects that need them. There you go! When the game starts, they register themselves, and you can get all your entities from the manager.


I hope it gives you an idea on how to deal with getting GameObjects in the scene without having to crawl through the whole hierarchy, or running into other potential bugs.