Search Unity

Question Missing element in a list (should be empty).

Discussion in 'Scripting' started by samumv33, Jun 1, 2023.

  1. samumv33

    samumv33

    Joined:
    Oct 16, 2022
    Posts:
    8
    Hello,

    im currently learning C# and Unity, and I found a problem I dont understand, lets see if someone can help me.

    The game works like this:

    -A Manager Object instantiates enemies inside another object (WPT). That object contains waypoints to control where the enemies can move. WTP has 2 lists, one with the waypoints and other one with the enemies that contain. The enemies list updates every time an enemy gets destroyed through an event and after checking the list of enemies it checks if the list is empty so, if it is empty the WTP objects is destroyed.

    So the problem is, the first WTP object instantiated when checks the list of enemies instead of empty (and destroyed), in the inpector, it shows "Missing".

    1st WPT.jpg 2nd WPT.jpg

    The enemy is destroyed, so:
    Empty List.jpg Missing List.jpg

    Why two clone objects, with the same code, in the same situation behave different?

    NOTE: I know I should be pooling all of this objects instead of instantiating and destroying them, but im currently learning how pooling works. Anything else I can improve is welcome!

    This is the code of the WTP object wich checks the list:

    Code (CSharp):
    1. public class WaypointTemplate : MonoBehaviour {
    2.     [SerializeField] private List<Waypoints> waypointsList;
    3.     [SerializeField] private List<Enemy> enemiesList;
    4.  
    5.     private void Start() {
    6.         waypointsList = new List<Waypoints>();
    7.         enemiesList = new List<Enemy>();
    8.  
    9.         SetWaypointsList();
    10.         SetEnemyList();
    11.     }
    12.     private void Awake() {
    13.         Explosion.OnAnyEnemyDestroyed += Explosion_OnAnyEnemyDestroyed;
    14.     }
    15.  
    16.     private void Explosion_OnAnyEnemyDestroyed() {
    17.         UpdateEnemiesList();
    18.         DestroyWhenEmpty();
    19.     }
    20.  
    21.     private void SetWaypointsList() {
    22.      waypointsList.AddRange(GetComponentsInChildren<Waypoints>());
    23.     }
    24.  
    25.     public void SetEnemyList() {
    26.         enemiesList.AddRange(GetComponentsInChildren<Enemy>());
    27.     }
    28.  
    29.     public List<Waypoints> GetWaypointsList() {
    30.         return waypointsList;
    31.     }
    32.  
    33.     private void DestroyWhenEmpty() {
    34.         if (enemiesList.Count == 0) {
    35.  
    36.             Explosion.OnAnyEnemyDestroyed -= Explosion_OnAnyEnemyDestroyed;
    37.  
    38.             Destroy(this.gameObject);
    39.         }
    40.     }
    41.     private void UpdateEnemiesList() {
    42.         enemiesList.Clear();
    43.         SetEnemyList();
    44.     }
    45. }
     
  2. samumv33

    samumv33

    Joined:
    Oct 16, 2022
    Posts:
    8
    Anybody?
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,736
    Anything you make public or serializable will become subject to this:

    Serialized properties in Unity are initialized as a cascade of possible values, each subsequent value (if present) overwriting the previous value:

    - what the class constructor makes (either default(T) or else field initializers, eg "what's in your code")

    - what is saved with the prefab

    - what is saved with the prefab override(s)/variant(s)

    - what is saved in the scene and not applied to the prefab

    - what is changed in Awake(), Start(), or even later etc.

    Make sure you only initialize things at ONE of the above levels, or if necessary, at levels that you specifically understand in your use case. Otherwise errors will seem very mysterious.

    If something doesn't NEED to be public, DO NOT make it public.

    Here's the official discussion: https://blog.unity.com/technology/serialization-in-unity

    Field initializers versus using Reset() function and Unity serialization:

    https://forum.unity.com/threads/sensitivity-in-my-mouselook-script.1061612/#post-6858908

    https://forum.unity.com/threads/crouch-speed-is-faster-than-movement-speed.1132054/#post-7274596

    As for why a particular instance is missing / null, there's only three steps, no other approach:

    How to fix a NullReferenceException error

    https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

    Three steps to success:
    - Identify what is null <-- any other action taken before this step is WASTED TIME
    - Identify why it is null
    - Fix that
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,925
    Are they referencing the same enemy? If so, then one of these will run before the other and clear itself out, and other will just be referencing a destroyed game object.
     
  5. samumv33

    samumv33

    Joined:
    Oct 16, 2022
    Posts:
    8
    Thx for the answer.

    No each one references different enemies, there is other object that instantiates both, they WPT and the Enemy being the enemy child of the WPT. Each of both in the Start method, get the reference in child or parent.

    The problem is the first one instantiated behaves different than the second. I mean, if I instantiate one, shows missing, but the second one shows an empty list and gets destroyed (as it sould be).
     
  6. samumv33

    samumv33

    Joined:
    Oct 16, 2022
    Posts:
    8
    Hello, thx for the answer, but I dont get how your message helps me. The list is private, it was only serialized to see if it was empty, changing that changes nothing.

    I identify what was null/ missing but I cant find why, that was the post about.

    Why the second object behaves different.
     
  7. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,110
    I think you've stumbled upon some fringe behavior in Unity, and it is likely that it is inconsistent because you're usage is abnormal. If I had to guess, and you can test this by making more than 2 of these objects, only one of them "gets the memo", the others don't (they actually show the infamous "fake null" object). This would explain why these are different: it's likely that just one of these is different from the rest (the first or the last one).

    I can't explain why exactly this would be the case, it's just my hunch.
     
  8. samumv33

    samumv33

    Joined:
    Oct 16, 2022
    Posts:
    8
    What part of the use is abmormal?

    I mean, what other way can I manage to update the list during run time?

    If i dont clear the List every time i update it, it starts growing.
     
  9. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,110
    I believe something is abnormal with that use case. That means the exact behavior you have going on is not a regular typical occurrence against which the editor has been tested. Not that you're doing something wrong. But that's only my opinion at this point. I cannot prove it unless I have your code to analyze it.

    I don't know. It's always specific, there are a ton of things that could've gone wrong.

    My advice to you is to try again with something smaller, something you can copy/paste in its entirety. If you can get the same behavior, share that with us, and we'll try to understand what's wrong with it and how it could be made better.