Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug C# Array Alternating Between Populated and Unpopulated?

Discussion in 'Editor & General Support' started by rb2kUnity, Jul 31, 2023.

  1. rb2kUnity

    rb2kUnity

    Joined:
    Jul 9, 2023
    Posts:
    3
    RESOLVED! Thank you to Kurt-Dekker for their insights.

    Hello. This is my first post.

    I am new to game dev but have some education in coding. I am attempting to load sprites into a sprite array in the inspector. However, the length of the array appears to change twice during the start() function of the class and its length alternates between 0 and 3 every frame. I cannot reference a location with a method in the array, as it throws an error saying any position is out of bounds. I am unsure how to diagnose this and am looking for guidance.

    Context: The Class that uses the array is a checker class with checker methods. Which means its methods are called by another Class. However, the object it is attached to is loaded into the scene at the start. I am not really using update or start other than to Debug.Log.

    Images: ----------------------------------------------------------------------------------------------------------------------------



    Code: (I included comments in the code related to this issue and removed all other comments) ------------------------------------------------------------------------------------------------
    Class using array.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class SymbolChecker : MonoBehaviour
    6. {
    7.     public GameObject character;
    8.     public Transform symbolHolderTransform;
    9.     public Sprite[] symbolSprites; //<------------------Array sprites are being loaded into via inspector.
    10.     public Sprite[] completedSymbolSprites;
    11.     public GameObject prefab;
    12.  
    13.     private void Start()
    14.     {
    15.         Debug.Log("Start " + symbolSprites.Length); //<---------------------- Writes an array length of 0 then 3(expected). Looks like it is called twice.
    16.     }
    17.  
    18.     private void Update()
    19.     {
    20.         Debug.Log("Update " + symbolSprites.Length); //<---------------------- Writes an array length of 0 then 3, alternating every frame.
    21.     }
    22.  
    23.     public bool ExcludedCheck(bool keyPressed) //<-------- Excluded checker.
    24.     {
    25.         bool result = false;
    26.  
    27.         switch (keyPressed)
    28.         {
    29.             case true:
    30.                 if (Input.GetKeyDown(KeyCode.W))
    31.                 {
    32.                     result = true;
    33.                     break;
    34.                 }
    35.                 else if (Input.GetKeyDown(KeyCode.A))
    36.                 {
    37.                     result = true;
    38.                     break;
    39.                 }
    40.                 else if (Input.GetKeyDown(KeyCode.S))
    41.                 {
    42.                     result = true;
    43.                     break;
    44.                 }
    45.                 else if (Input.GetKeyDown(KeyCode.D))
    46.                 {
    47.                     result = true;
    48.                     break;
    49.                 }
    50.                 else if (Input.GetKeyDown(KeyCode.Space))
    51.                 {
    52.                     result = true;
    53.                     break;
    54.                 }
    55.                 else if (Input.GetKeyDown(KeyCode.Mouse0))
    56.                 {
    57.                     result = true;
    58.                     break;
    59.                 }
    60.                 else if (Input.GetKeyDown(KeyCode.Mouse1))
    61.                 {
    62.                     result = true;
    63.                     break;
    64.                 }
    65.                 else if (Input.GetKeyDown(KeyCode.Alpha1))
    66.                 {
    67.                     result = true;
    68.                     break;
    69.                 }
    70.                 else if (Input.GetKeyDown(KeyCode.Alpha2))
    71.                 {
    72.                     result = true;
    73.                     break;
    74.                 }
    75.                 else if (Input.GetKeyDown(KeyCode.Alpha3))
    76.                 {
    77.                     result = true;
    78.                     break;
    79.                 }
    80.                 else if (Input.GetKeyDown(KeyCode.Alpha4))
    81.                 {
    82.                     result = true;
    83.                     break;
    84.                 }
    85.                 else if (Input.GetKeyDown(KeyCode.Tab))
    86.                 {
    87.                     result = true;
    88.                     break;
    89.                 }
    90.                 else if (Input.GetKeyDown(KeyCode.CapsLock))
    91.                 {
    92.                     result = true;
    93.                     break;
    94.                 }
    95.                 else if (Input.GetKeyDown(KeyCode.LeftShift))
    96.                 {
    97.                     result = true;
    98.                     break;
    99.                 }
    100.                 else if (Input.GetKeyDown(KeyCode.LeftControl))
    101.                 {
    102.                     result = true;
    103.                     break;
    104.                 }
    105.                 else if (Input.GetKeyDown(KeyCode.LeftAlt))
    106.                 {
    107.                     result = true;
    108.                     break;
    109.                 }
    110.                 else
    111.                 {
    112.                     result = false;
    113.                     break;
    114.                 }
    115.             default:
    116.                 result = false;
    117.                 break;
    118.  
    119.  
    120.         }
    121.  
    122.         return result;
    123.     }
    124.  
    125. //This is the method that uses the array. I currently only have a debug to display the length. Which always returns 0.
    126.     public bool SymbolCheck(int spellType, bool excluded, char[] reqInput, int arrayPos)
    127.     {
    128.  
    129.         Debug.Log(completedSymbolSprites.Length); //<-------- This writes an array length of 0 when this method is called. (global varliable)
    130.  
    131.         char charPress = 'l';
    132.         bool result;
    133.  
    134.         switch (spellType)
    135.         {
    136.             case 1:
    137.                 if (Input.GetKeyDown(KeyCode.Q) && excluded == false)
    138.                 {
    139.                     charPress = 'q';
    140.                     break;
    141.                 }
    142.                 else if (Input.GetKeyDown(KeyCode.E) && excluded == false)
    143.                 {
    144.                     charPress = 'e';
    145.                     break;
    146.                 }
    147.                 else if (Input.GetKeyDown(KeyCode.R) && excluded == false)
    148.                 {
    149.                     charPress = 'r';
    150.                     break;
    151.                 }
    152.                 else if (Input.GetKeyDown(KeyCode.T) && excluded == false)
    153.                 {
    154.                     charPress = 't';
    155.                     break;
    156.                 }
    157.                 else if (Input.GetKeyDown(KeyCode.F) && excluded == false)
    158.                 {
    159.                     charPress = 'f';
    160.                     break;
    161.                 }
    162.                 else if (Input.GetKeyDown(KeyCode.G) && excluded == false)
    163.                 {
    164.                     charPress = 'g';
    165.                     break;
    166.                 }
    167.  
    168.                 else if (Input.GetKeyDown(KeyCode.C) && excluded == false)
    169.                 {
    170.                     charPress = 'c';
    171.                     break;
    172.                 }
    173.                 else
    174.                 {
    175.                     break;
    176.                 }
    177.             default:
    178.                 break;
    179.  
    180.  
    181.         }
    182.      
    183.         if (charPress == reqInput[arrayPos])
    184.         {
    185.          
    186.             GameObject newSymbol = Instantiate(prefab);
    187.          
    188.             result = true;
    189.         }
    190.         else
    191.         {
    192.             result = false;
    193.         }
    194.  
    195.         return result;
    196.     }
    197. }
    198.  
    199.  
    Class code snippet calling the methods.
    Code (CSharp):
    1. case CastState.casting:
    2.  
    3.                 if (castTime > 0 && castComplete == false)
    4.                 {
    5.                     CastInputs(); //<----- ---------------------- Method that calls array class method.
    6.                     ReduceSlomo();
    7.  
    8.                     castTime -= Time.deltaTime;
    9.                 }
    10.                 else if (castTime <= 0 || castComplete == true)
    11.                 {
    12.                     //Return time to normal speed.
    13.                     Time.timeScale = originalTimeFactor;
    14.  
    15.                     Instantiate(bolasPrefab, castPoint.position, castPoint.rotation);
    16.  
    17.                     //Change state
    18.                     state = CastState.cooldown;
    19.                     castingTracker = false;
    20.                     controller.IsCasting(castingTracker);
    21.  
    22.                     //Enter cooldown.
    23.                     cooldownTime = spell.cooldownTime;
    24.  
    25.                     //Cast spell.
    26.                     spell.CastThisSpell(gameObject);
    27.                 }
    28.  
    29.                 break;
    CastInputs() code. (Mehtod that calls the method in the Checker class.)
    Code (CSharp):
    1. public void CastInputs()
    2.     {
    3.         bool keyPressed;
    4.         char[] reqArray = spell.keyReq;
    5.         int arrayLength = reqArray.Length;
    6.         bool[] hitArray = new bool[arrayLength];
    7.         bool keyExcluded;
    8.  
    9.         if (Input.anyKeyDown && arrayPos <= (arrayLength - 1))
    10.         {
    11.             keyPressed = true;
    12.  
    13.             keyExcluded = symbolChecker.ExcludedCheck(keyPressed); ////<-------- Method calling class using the array.
    14.  
    15.             if (keyExcluded == false)
    16.             {
    17.                 hitArray[arrayPos] = symbolChecker.SymbolCheck(type, keyExcluded, reqArray, arrayPos); //^-----------------------------------------------------Method calling class using the array.
    18.  
    19.                 arrayPos++;
    20.             }
    21.         }
    22.  
    23.         if (arrayPos > arrayLength -1)
    24.         {
    25.             //arrayPos.
    26.             arrayPos = 0;
    27.          
    28.             //Cast complete marker.
    29.             castComplete = true;
    30.         }
    31.  
    32.     }
    Note: The method is being called within a nested if statement BUT the start and update functions of the class using the array happen without calling the specific method.

    Any insight would be appreciated and thank you to anyone who took the time to look at this.
     
    Last edited: Jul 31, 2023
    Kurt-Dekker likes this.
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,560
    Easy! Here are some notes on IndexOutOfRangeException and ArgumentOutOfRangeException:

    http://plbm.com/?p=236

    Steps to success:
    - find which collection it is and what line of code accesses it <--- critical first step!)
    - find out why it has fewer items than you expect
    - fix whatever logic is making the indexing value exceed the collection size
    - remember that a collection with ZERO elements cannot be indexed at all: it is empty
    - remember you might have more than one instance of this script in your scene/prefab
    - remember the collection may be used in more than one location in the code
    - remember that indices start at ZERO (0) and go to the count / length minus 1.

    This means with three (3) elements, they are numbered 0, 1, and 2 only.

    If you still have no idea what is happening, then it is ...

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    If your problem is with OnCollision-type functions, print the name of what is passed in!

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    "When in doubt, print it out!(tm)" - Kurt Dekker (and many others)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
    rb2kUnity likes this.
  3. rb2kUnity

    rb2kUnity

    Joined:
    Jul 9, 2023
    Posts:
    3
    Ok I used debug throughout the path of the project. To provide more details it appears that when start() is called in the class with the array it is called twice. The first time, the array has a length of 0, but the second time its has a length of 3. Now when I debug.log first during the method call, the sprite array only ever has a length of 0;

    So my thinking is that the checker method is being called before the class is loading the sprites into the array. But I do have the Checker class on an object in the scene, so my assumption is that it should load the array with sprites once the scene starts.

    I do not know where to go from here. How to confirm my thought or to resolve the issue of the array not being populated.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,560
    Sounds like you put more than one instance of the script in the scene or on the prefab!
     
  5. rb2kUnity

    rb2kUnity

    Joined:
    Jul 9, 2023
    Posts:
    3
    Absolutely right! I was reviewing my scene and found it attached to another object!

    I appreciate you taking your time. Thank you.
     
    Kurt-Dekker likes this.