Search Unity

I can't clear my list !

Discussion in 'Scripting' started by imposter_syndrom_incarnated, Sep 26, 2020.

  1. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    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
    Code (CSharp):
    1. public List<int> IDlist;
    while in the script of the prefab, I add elements inside this list
    Code (CSharp):
    1. public int id;
    2.     //this references the main class where all operations happen
    3.     public Overlap reference;
    4.     private void OnMouseDown()
    5.     {
    6.         print("you clicked ball number: " + id);
    7.         reference.IDlist.Add(id);
    8.         print("total IDs accumulated: " + reference.IDlist.Count);
    9.     }
    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! :)
     
    Last edited: Sep 26, 2020
  2. adehm

    adehm

    Joined:
    May 3, 2017
    Posts:
    369
    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?
     
  3. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    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.
    https://docs.unity3d.com/2017.3/Documentation/ScriptReference/NonSerializable.html

    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?
     
  4. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    Hi! Thank you so much for getting back :oops:
    My Overap randomly spawn balls/prefab of balls. This is the class:
    Code (CSharp):
    1. public class Overlap : MonoBehaviour
    2. {
    3.     private float xRandomPos, yRandomPos;
    4.     Vector3 finalRandomPos;
    5.     public int numToGenerate;
    6.  
    7.     public List<GameObject> listOfObjects;
    8.     public List<GameObject> NewlistOfObjects;
    9.     public List<int> IDlist;
    10.  
    11.     public GameObject background;
    12.     MeshCollider borders;
    13.  
    14.     void Start()
    15.     {
    16.         borders = background.GetComponent<MeshCollider>();
    17.         WrappedCoroutine();
    18.     }
    19.  
    20.     /// <summary>
    21.     /// For the Button to click
    22.     /// </summary>
    23.     public void WrappedCoroutine()
    24.     {
    25.         StartCoroutine(Coroutine());
    26.     }
    27.  
    28.     /// <summary>
    29.     /// Main method
    30.     /// </summary>
    31.     /// <returns></returns>
    32.     public IEnumerator Coroutine()
    33.     {
    34.         //coroutine
    35.         WaitForSeconds wait = new WaitForSeconds(1f);
    36.  
    37.         int randomItemFromListIndex;
    38.         GameObject randomItemFromList;
    39.  
    40.         int idNum = 1;
    41.         for (int i = 0; i < numToGenerate; i++)
    42.         {
    43.             //where to generate
    44.             xRandomPos = Random.Range(borders.bounds.min.x, borders.bounds.max.x);
    45.             yRandomPos = Random.Range(borders.bounds.min.y, borders.bounds.max.y);
    46.             finalRandomPos = new Vector3(xRandomPos, yRandomPos, 0f);
    47.        
    48.             //what to generate
    49.             randomItemFromListIndex = Random.Range(0, listOfObjects.Count);
    50.             randomItemFromList = listOfObjects[randomItemFromListIndex];
    51.        
    52.             //to detect collision so that the collided balls are not taken
    53.             var gameObject = Instantiate(randomItemFromList, finalRandomPos, Quaternion.identity);
    54.             gameObject.GetComponent<Renderer>().enabled = false;
    55.             yield return new WaitForFixedUpdate();
    56.             var hasCollided = gameObject.GetComponent<BallPrefab>().collided;
    57.             print("collided? " + hasCollided);
    58.             if (hasCollided == false)
    59.             {
    60.                 //ID provided to each ball to distinguish them when clicked
    61.                 gameObject.GetComponent<BallPrefab>().id = idNum++;
    62.                 NewlistOfObjects.Add(gameObject);
    63.             }
    64.         }
    65.         print("total balls minus those collided: " + NewlistOfObjects.Count);
    66.  
    67.         //loop to make the balls not collided appear on screen and check the IDs
    68.         for (int i = 0; i < NewlistOfObjects.Count; i++)
    69.         {
    70.             NewlistOfObjects[i].GetComponent<Renderer>().enabled = true;
    71.             print("ID of the ball " + i + " is " + NewlistOfObjects[i].GetComponent<BallPrefab>().id);
    72.             yield return wait;
    73.         }
    74.     }
    75.  
    76.     /// <summary>
    77.     /// Restarts the current scene when the button is clicked
    78.     /// </summary>
    79.     public void Restart()
    80.     {
    81.         SceneManager.LoadScene("Overlap");
    82.     }
    83.  
    84. }
    and this is the script attached to the ball Prefab, so each ball spawned in the scene would have this:
    Code (CSharp):
    1. public class BallPrefab : MonoBehaviour
    2. {
    3.  
    4.     public bool collided;
    5.     public int id;
    6.     //this references the main class where all operations happen
    7.     public Overlap reference;
    8.     void Start()
    9.     {
    10.         reference.IDlist.Clear();
    11.     }
    12.     private void OnMouseDown()
    13.     {
    14.         print("you clicked ball number: " + id);
    15.         reference.IDlist.Add(id);
    16.     }
    17.     void OnTriggerEnter2D(Collider2D other)
    18.     {
    19.         collided = true;
    20.     }
    21.  
    22. }
    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
    Code (CSharp):
    1. var totID = reference.IDlist.Count;
    2.                     //totBalls is giving the wrong value, by showing 0, so the list is is empty based on this
    3.                     var totBalls = reference.NewlistOfObjects.Count;
    4.                     print("total IDs: " + totID);
    5.                     print("total balls: " + totBalls);
    6.                     var IDsMoreThanBalls = totID > totBalls;
    7.                     print("more IDs? " + IDsMoreThanBalls);
    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 :(
     
    Last edited: Sep 27, 2020
  5. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    no it's not :(
     
  6. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,555
    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?
     
  7. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    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 :(
    upload_2020-9-28_19-23-34.png
     
    Last edited: Sep 28, 2020
  8. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    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
    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'
     
  9. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    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:
    Code (CSharp):
    1. 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<BallPrefab> 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.
     
  10. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    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
    upload_2020-9-28_22-2-14.png
    upload_2020-9-28_22-3-18.png
    upload_2020-9-28_22-4-10.png
    so it's
    Code (CSharp):
    1.                 NewlistOfObjects.Add(ball);
    2.  
    I changed gameObject to ball
     
    Last edited: Sep 28, 2020