Home > Software engineering >  How to use List<GameObject> insteal GameObject[] when instantiating and destroying objects?
How to use List<GameObject> insteal GameObject[] when instantiating and destroying objects?

Time:01-27

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

[ExecuteAlways]
public class SliderManager : MonoBehaviour
{
    public Slider slider;
    public List<GameObject> InstantiatedObjects = new List<GameObject>();
    public GameObject Model;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        SetSlider((int)slider.value);
    }

    protected void SetSlider(int x)
    {
        for (int i = 0; i < slider.value; i  )
        {
            bool mustBeAnObject = i < x;

            if ((mustBeAnObject) && (InstantiatedObjects[i] == null))
                InstantiatedObjects.Add(Instantiate(Model));
            else if ((!mustBeAnObject) && (InstantiatedObjects[i] != null))
            {
                if (!Application.isPlaying)
                {
                    InstantiatedObjects.RemoveAt(i);
                    DestroyImmediate(InstantiatedObjects[i]);
                }
                else
                {
                    InstantiatedObjects.RemoveAt(i);
                    Destroy(InstantiatedObjects[i]);
                }
            }
        }
    }
}

When i used array before :

public GameObject[] Objects = new GameObject[100];

it was working fine i looped over the Objects array but then i had a problem to remove items from the array when destroying the objects so i tried to switch the array to list and changed the name from Objects to InstantiatedObjects.

but now i'm getting in the editor all the time out of bound index exception error on the line 32:

if ((mustBeAnObject) && (InstantiatedObjects[i] == null))

ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <75633565436c42f0a6426b33f0132ade>:0) SliderManager.SetSlider (System.Int32 x) (at Assets/SliderManager.cs:32) SliderManager.Update () (at Assets/SliderManager.cs:23)

line 23 is the line inside the Update.

i know what it means the error but not sure how to fix it.

what i'm trying to do is to use the Slider to insatiate objects when sliding the slider to the right and to destroy/remove objects when moving to the left.

it was working fine with the array until i needed to remove items from the array that's why i switched to List

CodePudding user response:

if ((mustBeAnObject) && (InstantiatedObjects[i] == null))
            InstantiatedObjects.Add(Instantiate(Model));

This code here will cause errors. Its easy to understand in the first iteration but its the same in all the iterations. In the first iteration you are checking whether the object in the 0th position in the list InstantiatedObjects is null or not. But its obviously illegal because there is no 0th position. Unlike Array, List don't allocate memory positions before they are provided with values to fill in them. So you cant ask the List to null check InstantiatedObjects[1] if there is only one element in the List.

CodePudding user response:

The moment you remove an object from the list (InstantiatedObjects.RemoveAt(0);) the list shrinks

=> all the later items are shifted down one index

=> all your later indices are wrong! Even directly in the next call already for e.g. DestroyImmediate(InstantiatedObjects[i]); this already refers to the item after the one you just removed!

You could rather do e.g.

// one loop for killing too many items
while(InstantiatedObjects.Count > slider.value)
{
    // could as well simply remove the first item if you prefer (0)
    var index = InstantiatedObjects.Count - 1;
    var item = InstantiatedObjects[index];
    InstantiatedObjects.RemoveAt(index);

    if (!Application.isPlaying)
    {
        DestroyImmediate(item);
    }
    else
    {
        Destroy(Item);
    }
}

// one loop for spawning missing items
while(InstantiatedObjects.Count > slider.value)
{
    InstantiatedObjects.Add(Instantiate(Model));
}
  • Related