Search Unity

Resolved An issue with an index variable and "Index out of range..." error when calling a method.

Discussion in 'Scripting' started by gjaccieczo, Jul 22, 2021.

  1. gjaccieczo

    gjaccieczo

    Joined:
    Jun 30, 2021
    Posts:
    306
    My HeroListScript script

    Code (CSharp):
    1.  
    2.     using System.Collections;
    3.     using System.Collections.Generic;
    4.     using System.IO;
    5.     using UnityEngine;
    6.     using Newtonsoft.Json;
    7.  
    8.     public class HeroListScript
    9.     {
    10.         List<HeroConstructor> heroList = new List<HeroConstructor>();
    11.         public int indexHero;
    12.         void Start()
    13.         {
    14.            ;
    15.         }
    16.  
    17.  
    18.     public class Deserializer
    19.     {
    20.         public static void DeserializingRootItem()
    21.         {
    22.             string jsonPath;
    23.             jsonPath = File.ReadAllText(Application.dataPath + "/list_of_heroes.json");
    24.             RootItem deserializedHero = JsonConvert.DeserializeObject<RootItem>(jsonPath);
    25.             HeroListScript heroListScript = new HeroListScript();
    26.             int indexHero1 = heroListScript.indexHero;
    27.             int heroNumberFromJson = deserializedHero.heroes[indexHero1].heroNumber;
    28.             string heroNameFromJson = deserializedHero.heroes[indexHero1].heroName;
    29.  
    30.             HeroConstructor hero1 = HeroConstructor(heroNumberFromJson, heroNameFromJson, 4);
    31.             HeroConstructor hero2 = HeroConstructor(heroNumberFromJson, heroNameFromJson, 2);
    32.             heroListScript.heroList.Add(hero1);
    33.             heroListScript.heroList.Add(hero2);
    34.             Debug.Log(hero1.heroName);
    35.             Debug.Log(hero2.heroName);
    36.  
    37.         }
    38.  
    39.     }
    40.  
    41.        public class HeroConstructor
    42.       {
    43.            public int heroNumber;
    44.            public string heroName;
    45.            public int indexHero;
    46.            HeroListScript heroListScript1 = new HeroListScript();
    47.  
    48.            public HeroConstructor(int heroNumberFromJson, string heroNameFromJson, int indexHero1)
    49.            {
    50.                   heroNumber = heroNumberFromJson;
    51.                   heroName = heroNameFromJson;
    52.                   indexHero = indexHero1;
    53.            }
    54.        }
    55.  
    56.     [System.Serializable]
    57.     public class RootItem
    58.     {
    59.         [JsonProperty("heroes")]
    60.         public List<Hero> heroes { get; set; }
    61.     }
    62.  
    63.     [System.Serializable]
    64.         public class Hero
    65.         {
    66.             [JsonProperty("heroNumber")]
    67.             public int heroNumber { get; set; }
    68.             [JsonProperty("heroName")]
    69.             public string heroName { get; set; }
    70.  
    71.         }
    72.     }

    My NewBehaviourScript that calls it.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class NewBehaviourScript : MonoBehaviour
    6. {
    7.     // Start is called before the first frame update
    8.     void Start()
    9.     {
    10.         Debug.Log("NewBehaviourScript is called!");
    11.         HeroListScript.Deserializer.DeserializingRootItem();
    12.         HeroListScript heroListScript = new HeroListScript();
    13.         Debug.Log(heroListScript.heroList[1].heroName);
    14.  
    15.     }
    16.  
    17.     // Update is called once per frame
    18.     void Update()
    19.     {
    20.  
    21.     }
    22. }
    23.  
    What i'm trying to achieve:
    • i'd like to put an int as the indexHero1 of my constructor and generate an object for the respective entry of the deserialized list that i have. An example of what i'm trying to do is in the Deserializer() method of HeroListScript, where i create item1 and item2 of the type HeroConstructor. (lines 30/31 of the HeroListScript).
    • i'd like to be able to access the heroList of HeroListScript from other scripts without any issues.
    What i'm getting:
    • regardless of what number i put as the last parameter of my hero1/hero2, i always get the data of the first entry in the list.
    • assigning a value to indexHero of the HeroListScript of 3 for example, prints out the heroName of the respective hero. (Deserializer method).
    • trying to call Debug.Log on the heroList with added items results in a " Index was out of range. Must be non-negative and less than the size of the collection." error. Referencing indexHero of HeroListScript as an index results in the same problem.
    Thank you in advance for your help!
     
    Last edited: Jul 22, 2021
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,187
    You're getting index out of range because your list is empty when you call heroList[1], even though it is intialized, it's an empty list. You need to make sure the list is populated before you try to access the values from other scripts.

    Now, to be clear, it's empty because your Deserializer creates a new HeroListScript and then in Start you are creating another new HeroListScript. These are not one and the same.

    For that fact, once your Deserializer is done running, it's basically going to toss away that instance of HeroListScript
     
    gjaccieczo likes this.
  3. gjaccieczo

    gjaccieczo

    Joined:
    Jun 30, 2021
    Posts:
    306
    Hmm, that explains it. I made a method in the HeroListScript that debug.logs the list outside of the Deserializer method and it returns the same index error, will try to make it a habit to check it using the method in the class rather than jumping to trying it outside of the class.

    I have a heroList that is created at the top of the script. I can't do much with it other what is already done in the script so it's not a culprit.

    I decided to pass the list as a parameter to the Deserializer method and then return it with the added values. Then i tried debug logging the heroList from another script and it...worked! Hurray! However it still shows up the first entry of the list and my constructor continues to ignore the indexHero1 values.

    The lines 30/31 of the HeroListScript are what i'm trying to fix. The ints that i added at the end don't seem to do anything at all. Do you have any clue why it does not work? The last explanation that you gave was quite effective, thank you!:D
     
    Last edited: Jul 23, 2021
  4. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,187
    What do you expect the ints to do?
    You are creating two instances of HeroConstructor and just assigning the values from the constructor to variables. And each one creates a list and doesn't seem to do anything with that list. Then I see you are adding those values to another list, which means index 0 and 1 of heroListScript are now occupied.

    When you do the Debug.Log statements, you're simply asking it to print out the heroName variable. I'm not sure what the purpose of the indexHero is.
     
  5. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    You can make one static list and make sure you always use this same list, you can make it betterr later.
     
  6. gjaccieczo

    gjaccieczo

    Joined:
    Jun 30, 2021
    Posts:
    306
    I expect indexHero (indexHero1 in the Deserializer method) to replace the whatever index there is in the deserializedHero.heroes (line 27/28 of HeroListScript).
    I'll break it down:
    • Let's say i have a deserialized list of with 4 entries. Those entries go from 0 to 3. Usually if i wanted to just debug.log that list i'd do something like:
      Code (CSharp):
      1. Debug.Log(list.items[0].aName)
      where the square brackets have the index of whatever item i'd like to debug.log. However, given that i have a constructor, i don't see any other option to input the index other than making indexHero1 whatever index i want it to be. Adding items as of now results into item1 and item2 just containing the data of the first entry of the deserialized list. What i'm trying to achieve is:
    Code (CSharp):
    1. HeroConstructor hero1 = HeroConstructor(heroNumberFromJson, heroNameFromJson, 0);
    2. HeroConstructor hero2 = HeroConstructor(heroNumberFromJson, heroNameFromJson, 1);
    3. HeroConstructor hero3 = HeroConstructor(heroNumberFromJson, heroNameFromJson, 2);
    4. HeroConstructor hero4 = HeroConstructor(heroNumberFromJson, heroNameFromJson, 3);
    5.  
    6. heroListScript.heroList.Add(hero1);
    7. heroListScript.heroList.Add(hero2);
    8. heroListScript.heroList.Add(hero3);
    9. heroListScript.heroList.Add(hero4);
    10.  
    11. Debug.Log(hero1.heroName);
    12. Debug.Log(hero2.heroName);
    13. Debug.Log(hero3.heroName);
    14. Debug.Log(hero4.heroName);
    15.  
    16.  
    which should result in the heroName of the list entries of indices 0, 1, 2, 3 to be displayed.

    I tried just changing the heroIndex1 in the method while also removing the heroIndex completely and leaving only one in the method:

    Code (CSharp):
    1. HeroConstructor hero1 = HeroConstructor(heroNumberFromJson, heroNameFromJson);
    2. heroIndex1 = 1;
    3. HeroConstructor hero2 = HeroConstructor(heroNumberFromJson, heroNameFromJson);
    4. heroIndex = 2;
    5. HeroConstructor hero3 = HeroConstructor(heroNumberFromJson, heroNameFromJson);
    6.  
    but it still shows up the first entry regardless.

    Update: after typing it all out i realized that i just add an int to the objects that are created of the type HeroConstructor which is impossible to be input to the indexInt1 because it occurs AFTER the creation of the object. But changing the indexInt1 on it's own before the object initialization occurs does not work as well so i'm really unsure what it could be.
     
    Last edited: Jul 24, 2021
  7. gjaccieczo

    gjaccieczo

    Joined:
    Jun 30, 2021
    Posts:
    306
    I know that and thanks for the tip but unfortunately it doesn't really resolve my current issue. :)