I can't clear my list !

Hello,
I have a question.
I have a prefab with it’s script and the main GameObject with it’s script, where the main aspects of the game happen. In this main script I have initialized a list

public List<int> IDlist;

while in the script of the prefab, I add elements inside this list

public int id;
    //this references the main class where all operations happen
    public Overlap reference;
    private void OnMouseDown()
    {
        print("you clicked ball number: " + id);
        reference.IDlist.Add(id);
        print("total IDs accumulated: " + reference.IDlist.Count);
    }

When the scene reloads or when I play the game again, I expect the list to be emptied. Here is the problem: I can’t empty the list in any ways from the main script but can only do so from the script of the prefab (as long as I add a Start() to the script above with reference.IDlist.Clear() inside). Why can’t I clear the list from the class it was initialized in?
I first put IDlist.Clear() in the Start() of the main script that generates the balls and it didn’t work, then I put it in the beginning of the main method (a coroutine that generates the balls) still didn’t work, then I put it in the method to reload the scene, still no luck. The IDs just kept accumulating.

The question is, why is it that I can clear this list only in the class where it is “imported”/used via a reference to the object.

Any explanation would be greatly appreciated! :slight_smile:

When the scene reloads it certainly should be empty because the script will be created new; is your main static because then it would not?

Try adding the [NonSerialized] attribute to your list definition. By default Unity tries to serialize public variables of certain types (mostly primitives). I assume this also includes lists of integers. NonSerialized will also stop it from showing up in the inspector tho. If that is still wanted, add ShowInInspector as well.

That should at least stop the value from being saved between sessions. As for why you cannot clear the list in your Overlap object - i dont know. But i dont think based on the information you provided there is a way to know. You’ll have to provide some more information. Like actual code examples of what you tried and did not work.
Also i’m assuming the class (Overlap) inherits from Monobehaviour and is attached to an enabled gameobject, which does not contain a script making it DontDestroyOnLoad?

Hi! Thank you so much for getting back :sweat_smile:
My Overap randomly spawn balls/prefab of balls. This is the class:

public class Overlap : MonoBehaviour
{
    private float xRandomPos, yRandomPos;
    Vector3 finalRandomPos;
    public int numToGenerate;
 
    public List<GameObject> listOfObjects;
    public List<GameObject> NewlistOfObjects;
    public List<int> IDlist;
 
    public GameObject background;
    MeshCollider borders;

    void Start()
    {
        borders = background.GetComponent<MeshCollider>();
        WrappedCoroutine();
    }

    /// <summary>
    /// For the Button to click
    /// </summary>
    public void WrappedCoroutine()
    {
        StartCoroutine(Coroutine());
    }

    /// <summary>
    /// Main method
    /// </summary>
    /// <returns></returns>
    public IEnumerator Coroutine()
    {
        //coroutine
        WaitForSeconds wait = new WaitForSeconds(1f);

        int randomItemFromListIndex;
        GameObject randomItemFromList;

        int idNum = 1;
        for (int i = 0; i < numToGenerate; i++)
        {
            //where to generate
            xRandomPos = Random.Range(borders.bounds.min.x, borders.bounds.max.x);
            yRandomPos = Random.Range(borders.bounds.min.y, borders.bounds.max.y);
            finalRandomPos = new Vector3(xRandomPos, yRandomPos, 0f);
       
            //what to generate
            randomItemFromListIndex = Random.Range(0, listOfObjects.Count);
            randomItemFromList = listOfObjects[randomItemFromListIndex];
       
            //to detect collision so that the collided balls are not taken
            var gameObject = Instantiate(randomItemFromList, finalRandomPos, Quaternion.identity);
            gameObject.GetComponent<Renderer>().enabled = false;
            yield return new WaitForFixedUpdate();
            var hasCollided = gameObject.GetComponent<BallPrefab>().collided;
            print("collided? " + hasCollided);
            if (hasCollided == false)
            {
                //ID provided to each ball to distinguish them when clicked
                gameObject.GetComponent<BallPrefab>().id = idNum++;
                NewlistOfObjects.Add(gameObject);
            }
        }
        print("total balls minus those collided: " + NewlistOfObjects.Count);

        //loop to make the balls not collided appear on screen and check the IDs
        for (int i = 0; i < NewlistOfObjects.Count; i++)
        {
            NewlistOfObjects[i].GetComponent<Renderer>().enabled = true;
            print("ID of the ball " + i + " is " + NewlistOfObjects[i].GetComponent<BallPrefab>().id);
            yield return wait;
        }
    }
 
    /// <summary>
    /// Restarts the current scene when the button is clicked
    /// </summary>
    public void Restart()
    {
        SceneManager.LoadScene("Overlap");
    }

}

and this is the script attached to the ball Prefab, so each ball spawned in the scene would have this:

public class BallPrefab : MonoBehaviour
{
 
    public bool collided;
    public int id;
    //this references the main class where all operations happen
    public Overlap reference;
    void Start()
    {
        reference.IDlist.Clear();
    }
    private void OnMouseDown()
    {
        print("you clicked ball number: " + id);
        reference.IDlist.Add(id);
    }
    void OnTriggerEnter2D(Collider2D other)
    {
        collided = true;
    }
 
}

I noticed that the global variables are being problematic.

  1. By using the ‘reference’ in the BallPrefab class I had to clear the list, as I could not do that in the main class/Overlap class. Why so?
  2. By using the ‘reference’ in the BallPrefab class however I could not get the value of the length of the NewlistOfObjects right, because it kept giving me 0 as the length, wrongly. I have tested this by putting this bit of code inside the OnMouseDown() of the BallPrefab
var totID = reference.IDlist.Count;
                    //totBalls is giving the wrong value, by showing 0, so the list is is empty based on this
                    var totBalls = reference.NewlistOfObjects.Count;
                    print("total IDs: " + totID);
                    print("total balls: " + totBalls);
                    var IDsMoreThanBalls = totID > totBalls;
                    print("more IDs? " + IDsMoreThanBalls);

6353322--706494--upload_2020-9-27_0-29-25.png

Summary: I am struggling to work between the two scripts for these reasons explained. Is there any gap in my understanding of how I should be referencing the scripts between each other? It was easier when I just used to work with C# and would use inheritance/composition relations. I seem to be clueless about what I am doing wrong on Unity :frowning:

no it’s not :frowning:

Make sure your BallPrefab doesn’t have “collided” enabled/checked in the Inspector? See if this helps either way… [NonSerialized] public bool collided = false;. Note that to use [NonSerialized] you need to be using System;

If that still doesn’t make it work… Is your object with the Overlap component visible in scene hierarchy’s DontDestroyOnLoad while in Play Mode?

Hey, I tried the NonSerialized method but it gives error when it’s NonSerialized in line 61 of the Overlap class in the comment above :frowning:
6358794--707424--upload_2020-9-28_19-23-34.png

Hi, thank you for the reply. collided is always checked off because it will be true only when it collides and the balls that collide are not taken in the
NewlistOfObjects. The collided boolean is not really the line that is not updating. Rather it is the total of the NewlistOfObjects that despite being updated in the Overlap class, you see here
6358851--707445--upload_2020-9-28_19-30-45.png
it still not not give the updated value in the class of the BallPrefab, where I import the reference of the Overlap class, as in fact it gives ‘total balls: 0’ in the console as you see despite ‘total balls minus the balls collided: 3’

I assume you set the variable through the inspector. As i already mentioned, you will have to add the ShowInInspector attribute to continue this functionality. In your current code the list is otherwise never instantiated, and thus a NullReferenceException may occur. Even tho, the line you mentioned (61 of the posted example) is this:

gameObject.GetComponent<BallPrefab>().id = idNum++;

Which should be completely unaffected by adding NonSerialized to your IDlist.

Edit: I just realised you have a custom variable called “gameObject”. Change that in the future. It’s highly confusing since Unity also has its own shortcut gameObject variable for accessing the gameobject of the current script.
The more i think about it, the less i see how a NullReferenceException could happen in line 61. Are you sure that’s the correct line? The thing is, if (your) “gameObject” was null, the exception would occur in line 54. If GetComponent was null, the exception would occur in line 56. The rest of line 61 is bools and integers, which cannot be null. This is probably unrelated but I’d also advice not using ‘var’ for lazy reasons. Just write the correct type there instead. This saves you a lot of headache, especially as a beginner, since the engine can tell you about possible type mismatches at the correct location. Just act as if ‘var’ did not exist in C# and later (if you still care) use it again for rare specific reasons.

Hey, thank you for the reply. I didn’t set it through inspector. 61 was a typo so the wrong line number even though I even attached the picture that it was line 81, I am attaching the pictures again. Apologies for the inconvenience !
As I make the change
6359394--707565--upload_2020-9-28_22-2-14.png
6359394--707568--upload_2020-9-28_22-3-18.png
6359394--707571--upload_2020-9-28_22-4-10.png
so it’s

                NewlistOfObjects.Add(ball);

I changed gameObject to ball