LOL LOl
LOL LOl

Reputation: 47

Argumentoutofrangeexception except it is not? C# unity

I am really new to coding and I have run into my first problem...4 hours after looking at it and I realise I probably need some help.

The code is for 4 buttons, all of which have a very similar code (in fact almost identical except for the ID variable), yet 2 of them say 'argumentoutofrangeexception index' when loaded, despite the index being the same. (or so I think)

I have linked below the code for one of the not working buttons and one of the other buttons which does work + the test control:

NOT WORKING BUTTON

public class Answer3script : MonoBehaviour {
    List<string> thirdchoice = new List<string>() { "first choice", "second choice", "third choice", "fourth", "fifth"};
    public static string answerCorrect3 = "n";

    void Update () {
        if (Textcontrol.randQuestion > -1)
        {
            GetComponentInChildren<Text>().text = thirdchoice[Textcontrol.randQuestion];
        }

        if (Textcontrol.correctAnswer[Textcontrol.randQuestion] == Textcontrol.buttonSelected)
        {
             answerCorrect3 = "y";
        }
    }
}

WORKING BUTTON

public class Answer2script : MonoBehaviour {
    List<string> secondchoice = new List<string>() { "first choice", "second choice", "third choice", "fourth choice", "fifth choice" };
    public static string answerCorrect2 = "n";

    void Update () {
        if (Textcontrol.randQuestion > -1)
        {
            GetComponentInChildren<Text>().text = secondchoice[Textcontrol.randQuestion];
        } 

        if (Textcontrol.correctAnswer[Textcontrol.randQuestion] == Textcontrol.buttonSelected)
        {
            answerCorrect2 = "y";

            //   if (answerCorrect2 == "y")
            //  {
            //      image.color = Color.green;
            //  }
        }
    }
}

TEXT CONTROL:

public class Textcontrol : MonoBehaviour {
    List<string> questions = new List<string>() { "This is the first question", "second", "third", "fourth", "fifth" };
    public static List<string> correctAnswer = new List<string>() { "Answer1", "Answer2", "Answer3", "Answer4", "Answer4" };

     public static string buttonSelected;
     public static string choiceSelected = "n";
     public static int randQuestion=-1;

     void Update () {
         Image image  = GameObject.Find("Answer1").GetComponent<Image>();
         Image image2 = GameObject.Find("Answer2").GetComponent<Image>();
         Image image3 = GameObject.Find("Answer3").GetComponent<Image>();
         Image image4 = GameObject.Find("Answer4").GetComponent<Image>();

         if (randQuestion == -1)
         {
             randQuestion = Random.Range(0, 5);
         }

         if (randQuestion > -1)
         {
             GetComponent<Text>().text = questions[randQuestion];
         }

         if (choiceSelected == "y")
         {
             choiceSelected = "n";

             if (correctAnswer[randQuestion] == buttonSelected)
             {
                 Debug.Log("Correct!");
             }
         }
     }
}

Apologies for the really badly formatted code, I couldn't get it to work!

Upvotes: 0

Views: 138

Answers (1)

derHugo
derHugo

Reputation: 90649

You have a race-condition here! The Update of Answer3script might be called before the one of Textcontrol so randQuestion could still have the default value -1

Solution 1

Instead of the first if you could in both Update()s simply do

private void Update()
{
    // Check if Textcontrol values are set already
    if (Textcontrol.randQuestion < 0 || Textcontrol.correctAnswer.Count < Textcontrol.randQuestion + 1 || Textcontrol.correctAnswer[Textcontrol.randQuestion] == null ) return;

    // ....
}

so if the Textcontrol is not ready yet than nothing happens.

The second condition || Textcontrol.correctAnswer.Count < Textcontrol.randQuestion + 1 makes sure the element with the index you are trying to access exists in the list.

Be aware that string values can be null! Therefore, the third condition || Textcontrol.correctAnswer[Textcontrol.randQuestion] == null makes sure the value at the index you access actually has a valid value. If you want to avoid empty string ("") as well, you caould also extend it to || string.IsNullOrEmpty(Textcontrol.correctAnswer[Textcontrol.randQuestion])


Solution 2

(I would prefer Solution 1)

Go to Edit-> Project Settings -> Script Execution Order
enter image description here

Click on the + and add your two scripts Answer2Script and Answer3Script. You also can simply drag them (one by one onto the field). Without giving Textcontrol a certain execution time here it will be executed in the DefualtTime block. So just make sure your two scripts are after the DefaultTime. Than hit Apply. This makes sure your two scripts always are executed after the Default Time -> after Textcontrol.

enter image description here

Upvotes: 1

Related Questions