Problems on removing a GameObject from a List

Sorry for my English… and sorry because my code is in Spanish

I have a problem… I make a List where I add GameObjects, if certain conditions are met, they are destroyed and removed from the List. The problem is when I remove and Destroy the last GO from the List… “The object of type ‘GameObject’ has been destroyed but you’re still trying to access to it”.

I think that the main problem is the “foreach”, it looks every space on the List, and the GameObjects that are removed and destroyed still have a presence on the List… How can i solve this? (problem in line 139)

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

public class principal : MonoBehaviour {
    public GameObject cubo;

    public int cola = 5;
    int CuboNumero = 1;
    int nivelCubo = 0;

    float subir = -3.5f;
    float constanteZ = -2.19f;
    float tiempo = 0;
    float tiempoMoverCubo;
    float AleatorioMenor = 0.15f, AleatorioMayor = 0.3f;

    bool volviendo = false;
    bool crearCubos = false;

    private List<GameObject> lista = new List<GameObject>();



    // Use this for initialization
    void Start () {
        CrearCubos();
    }
   
    // Update is called once per frame
    void Update () {
        tiempo = tiempo + Time.deltaTime;

        if (tiempo>=tiempoMoverCubo && crearCubos==false)
            MoverCubos();

        if (Input.GetKeyDown(KeyCode.Space) && crearCubos == false)
            PararCubos();

        if (tiempo>=1.5f && crearCubos==true)
            CrearCubos();
       
        BorrarCubos();
    }







    //creara los cubos cuando sea necesario / It will make the cubes when necessary
    void CrearCubos(){
        for (int i=0;i!=cola;i++)
        {
            cubo=(GameObject)GameObject.Instantiate(cubo, new Vector3(-4.5f + i,-4.5f + nivelCubo,constanteZ),Quaternion.identity);
            cubo.GetComponent<Identidad>().numero = CuboNumero;
            cubo.transform.name ="Cubo " + CuboNumero.ToString();
            cubo.renderer.material.color=Color.blue;
            cubo.GetComponent<Identidad>().activo = true;
            cubo.GetComponent<Identidad>().borrar = false;
            lista.Add(cubo);
            CuboNumero++;
        }
        crearCubos = false;
        tiempoMoverCubo=Random.Range(AleatorioMenor,AleatorioMayor);
        tiempo = 0f;
    }

    //Movera los cubos / it will moves the cubes
    void MoverCubos(){
        float siguiente = -1f;
        foreach (GameObject parte in lista){
                if (parte.GetComponent<Identidad>().activo == true)
                {
                    siguiente++;
                    parte.transform.position = new Vector3(subir + siguiente,-4.5f + nivelCubo,constanteZ);
                }
        }

        if (subir + siguiente==4.5f)
            volviendo=true;
        else if (subir==-4.5f)
            volviendo=false;

        if (volviendo==false)
            subir+=1f;
        else
            subir-=1f;

            tiempo=0f;
    }

    //parara los cubos / it will stop the cubes
    void PararCubos(){
        foreach (GameObject parte in lista){
                if (parte.GetComponent<Identidad>().activo == true){               
                    parte.GetComponent<Identidad>().activo = false;
                    parte.GetComponent<Identidad>().x = parte.transform.position.x + 5.5f;
                    parte.GetComponent<Identidad>().y = parte.transform.position.y + 5.5f;
                    if (parte.GetComponent<Identidad>().y!=1)
                        if (ComprobarCubos(parte))
                            parte.renderer.material.color = Color.green;
                        else{                   
                        cola--;
                        parte.renderer.material.color = Color.red;
                        parte.GetComponent<Identidad>().borrar = true;
                        }
                    else
                        parte.renderer.material.color = Color.green;
                }
        }
        ResetearParametros();
    }

    //reseteara los parametros que realizan el movimiento de los cubos / it will reset the parameters
    void ResetearParametros(){
        subir = -3.5f;       
        volviendo = false;
        nivelCubo++;
        crearCubos = true;
        AleatorioMenor = AleatorioMenor * 0.9f;
        AleatorioMayor = AleatorioMayor * 0.95f;
    }

    //comprobara si debajo de los cubos activos... hay cubos / it will check if there are cubes belows the actives
    bool ComprobarCubos(GameObject objeto){
        foreach (GameObject parte in lista)
        {
                if (parte.GetComponent<Identidad>().y + 1 == objeto.GetComponent<Identidad>().y)
                    if (parte.GetComponent<Identidad>().x == objeto.GetComponent<Identidad>().x)
                        return true;
        }
        return false;
    }

    //borrara los cubos / it will delete the cubes
    void BorrarCubos(){
        foreach (GameObject parte in lista){
                if (parte.GetComponent<Identidad>().borrar == true){
                lista.Remove(parte);
                Destroy(parte);
            }
        }
        //lista.RemoveAll( delegate(GameObject o) { return o == null;});
    }

    }

After a GameObject has been destroyed, any references to it will be NULL. Do a For loop instead of a foreach loop and check each slot for NULL, or use a list method like RemoveAll:

someList.RemoveAll(i => i == null);

before iterating over it.

2 Likes

try this instead:

for (int i = 0; i < lista.Count; i++)
            {
                GameObject parte = lista[i];
                if (parte.GetComponent<Identidad>().borrar == true)
                {
                    lista.RemoveAt(i);
                    i--;

                    Destroy(parte);
                }
            }

“MissingReferenceException: The object of type ‘GameObject’ has been destroyed but you’re still trying to access it”
still have the same problem… it happens when the last gameObject is removed

I tried this:

    void BorrarCubos(){
        for (int i = 0; i < lista.Count; i++)
        {
            GameObject parte = lista[i];
            if (parte.GetComponent<Identidad>().borrar == true)
            {
                i--;
               
                Destroy(parte);
            }
        }
        lista.RemoveAll(i => i == null);
        //lista.RemoveAll( delegate(GameObject o) { return o == null;});
    }

but Unity closes… after a GameObject is going to be destroyed

try this:

lista.RemoveAll(i => i == null);

before you iterate the list.

Edit: i just have seen the mistake: you are decreasing i but don’t remove the element from the list, so you stay at the same value for i forever (in theory). Therefore you try to destroy the game object in the next iteration again.
So you have to remove it from the list when you call i–;

I tried your code, but it is the same as mine. I have tried many codes, where all destroy it from the list, then remove it, some of them making a "if (lista == null)", Unity always say i’m trying to access to the destroyed object… is like the gameobject, even being null and being out from the list, still have a presence in the project…
I forget to remove the i-- from your code… but i have tried this:
```csharp

  •    for (int i = 0; i < lista.Count; i++)
      {
          GameObject parte = lista[i];
          if (parte.GetComponent<Identidad>().borrar == true)
          {               
              Destroy(parte);
          }
      }
      lista.RemoveAll(i => i == null);*
    

```
and it is still the same… the only difference is now I have this problem: “MissingReferenceException: The object of type ‘GameObject’ has been destroyed but you’re still trying to access it”, when any cube (gameobject) is removed from the game (not only the last).

try changing

if (parte.GetComponent<Identidad>().borrar == true)

to

if (parte != null && parte.GetComponent<Identidad>().borrar == true)
lista.Where(i => i != null && i.GetComponent<Identidad>().borrar).ToList().ForEach(j => Destroy(j));
lista.RemoveAll(i => i == null);

Just because I can. To be clear, this would replace the entire function.

EDIT: Written a little clearer:

List<GameObject> tempList = lista.Where(i => i != null && i.GetComponent<Identidad>().borrar == true).ToList();

foreach(GameObject GO in tempList)
{
   Destroy(GO);
}

lista.RemoveAll(i => i == null);

Same problem… it says the same when the last gameobject on the list is removed and destroyed. I also tried to change all “if’s” in all foreach, so it could check if the gameobject was already null… but still the same problem

please give us the current state:

  1. paste the source code of your current code.
  2. paste the error message together with the stack trace.

it seems i need a new “using” because list.where is not included on system.collection.generic

Le’s say this is the current code:

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

public class principal : MonoBehaviour {
    public GameObject cubo;

    public int cola = 5;
    int CuboNumero = 1;
    int nivelCubo = 0;

    float subir = -3.5f;
    float constanteZ = -2.19f;
    float tiempo = 0;
    float tiempoMoverCubo;
    float AleatorioMenor = 0.15f, AleatorioMayor = 0.3f;

    bool volviendo = false;
    bool crearCubos = false;

    private List<GameObject> lista = new List<GameObject>();



    // Use this for initialization
    void Start () {
        CrearCubos();
    }
   
    // Update is called once per frame
    void Update () {
        tiempo = tiempo + Time.deltaTime;

        if (tiempo>=tiempoMoverCubo && crearCubos==false)
            MoverCubos();

        if (Input.GetKeyDown(KeyCode.Space) && crearCubos == false)
            PararCubos();

        if (tiempo>=1.5f && crearCubos==true)
            CrearCubos();
       
        BorrarCubos();
    }







    //creara los cubos cuando sea necesario / It will make the cubes when necessary
    void CrearCubos(){
        for (int i=0;i!=cola;i++)
        {
            cubo=(GameObject)GameObject.Instantiate(cubo, new Vector3(-4.5f + i,-4.5f + nivelCubo,constanteZ),Quaternion.identity);
            cubo.GetComponent<Identidad>().numero = CuboNumero;
            cubo.transform.name ="Cubo " + CuboNumero.ToString();
            cubo.renderer.material.color=Color.blue;
            cubo.GetComponent<Identidad>().activo = true;
            cubo.GetComponent<Identidad>().borrar = false;
            lista.Add(cubo);
            CuboNumero++;
        }
        crearCubos = false;
        tiempoMoverCubo=Random.Range(AleatorioMenor,AleatorioMayor);
        tiempo = 0f;
    }

    //Movera los cubos / it will moves the cubes
    void MoverCubos(){
        float siguiente = -1f;
        foreach (GameObject parte in lista){
            if (parte.GetComponent<Identidad>().activo == true)
                {
                    siguiente++;
                    parte.transform.position = new Vector3(subir + siguiente,-4.5f + nivelCubo,constanteZ);
                }
        }

        if (subir + siguiente==4.5f)
            volviendo=true;
        else if (subir==-4.5f)
            volviendo=false;

        if (volviendo==false)
            subir+=1f;
        else
            subir-=1f;

            tiempo=0f;
    }

    //parara los cubos / it will stop the cubes
    void PararCubos(){
        foreach (GameObject parte in lista){
                if (parte.GetComponent<Identidad>().activo == true){               
                    parte.GetComponent<Identidad>().activo = false;
                    parte.GetComponent<Identidad>().x = parte.transform.position.x + 5.5f;
                    parte.GetComponent<Identidad>().y = parte.transform.position.y + 5.5f;
                    if (parte.GetComponent<Identidad>().y!=1)
                        if (ComprobarCubos(parte))
                            parte.renderer.material.color = Color.green;
                        else{                   
                        cola--;
                        parte.renderer.material.color = Color.red;
                        parte.GetComponent<Identidad>().borrar = true;
                        }
                    else
                        parte.renderer.material.color = Color.green;
                }
        }
        ResetearParametros();
    }

    //reseteara los parametros que realizan el movimiento de los cubos / it will reset the parameters
    void ResetearParametros(){
        subir = -3.5f;       
        volviendo = false;
        nivelCubo++;
        crearCubos = true;
        AleatorioMenor = AleatorioMenor * 0.9f;
        AleatorioMayor = AleatorioMayor * 0.95f;
    }

    //comprobara si debajo de los cubos activos... hay cubos / it will check if there are cubes belows the actives
    bool ComprobarCubos(GameObject objeto){
        foreach (GameObject parte in lista)
        {
            if (parte.GetComponent<Identidad>().y + 1 == objeto.GetComponent<Identidad>().y)
                if (parte.GetComponent<Identidad>().x == objeto.GetComponent<Identidad>().x)
                    return true;
        }
        return false;
    }

    //borrara los cubos / it will delete the cubes
    void BorrarCubos(){

        for (int i = 0; i < lista.Count; i++)
        {
            GameObject parte = lista[i];
            if (parte.GetComponent<Identidad>().borrar == true)
            {
                lista.RemoveAt(i);
                i--;
               
                Destroy(parte);
            }
        }
       
        /*List<GameObject> tempList = lista.Where(i => i != null && i.GetComponent<Identidad>().borrar).ToList();
       
        foreach(GameObject GO in tempList)
        {
            Destroy(GO);
        }
       
        lista.RemoveAll(i => i == null);*/
        //lista.RemoveAll( delegate(GameObject o) { return o == null;});
    }
   
}

and this is the error:
MissingReferenceException: The object of type ‘GameObject’ has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
UnityEngine.Object.Internal_InstantiateSingle (UnityEngine.Object data, Vector3 pos, Quaternion rot) (at C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineObject.cs:74)
UnityEngine.Object.Instantiate (UnityEngine.Object original, Vector3 position, Quaternion rotation) (at C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineObject.cs:84)
principal.CrearCubos () (at Assets/scripts/principal.cs:56)
principal.Update () (at Assets/scripts/principal.cs:41)

and again… the function where i remove the game object is at ln 138, and where i call it is in lv 43

the exception tells a different story:

so it is in line 56.

you are creating a game object from “cubo” and assign it to “cubo”. this doesn’t seem to be correct. assign it to a local variable instead. like this:

  for (int i=0;i!=cola;i++)
        {
            var tmp = (GameObject)GameObject.Instantiate(cubo, new Vector3(-4.5f + i,-4.5f + nivelCubo,constanteZ),Quaternion.identity);
            tmp.GetComponent<Identidad>().numero = CuboNumero;
            tmp.transform.name ="Cubo " + CuboNumero.ToString();
            tmp.renderer.material.color=Color.blue;
            tmp.GetComponent<Identidad>().activo = true;
            tmp.GetComponent<Identidad>().borrar = false;
            lista.Add(tmp);
            CuboNumero++;
        }
1 Like

Oh really… i was closed in the same function during a week… and the error was in another function… :O, thanks for the help… i need to see more the exception. It was weird, becuz the project worked fine, until i made the remove function (or BorrarCubos())

My last response uses extension methods that are likely made available in System.Linq, though they could be from System, System.Collections, or System.Collections.Generic.

1 Like