0

I have the following List:

public Question init()
{
     questions = new List<GameManager.Question>();
     questions.Add(new GameManager.Question("Ya no hay técnicas que te puedan salvar.", "Sí que las hay, sólo que nunca las has aprendido."));
     questions.Add(new GameManager.Question("Espero que tengas un barco para una rápida huida.", "¿Por qué? ¿Acaso querías pedir uno prestado?"));
     questions.Add(new GameManager.Question("Ahora entiendo lo que significan basura y estupidez.", "Me alegra que asistieras a tu reunión familiar diaria."));

     return questions;
}

I initialize the following buttons on start:

for (int i = 0; i < questionList.Count; i++)
{
    GameObject child = Instantiate(questionButton, buttonLayout.transform);
    child.GetComponent<Text>().text = questionList[i].answer;
    child.GetComponent<Button>().onClick.AddListener(() => QuestionCheck(i));
}

And I have the following code:

public void QuestionCheck(int index)
{
    if (currentQuestion.answer == questionList[index].answer)
    {
        playerAsk = 1;
        playerScore += 1;
        scorePlayer.GetComponent<Text>().text = "Jugador: " + playerScore;
        roundStatus.text = "Has ganado la ronda!";
        roundStatus.color = Color.green;
        correct.Play();
    }
}

I think it crashes on the following line:

if (currentQuestion.answer == questionList[index].answer)

Also if I try the following line it also crashes:

questionList.RemoveAt(index);

I obtain the following error:

ArgumentOutOfRangeException: Argument is out of range. Parameter name: index

Why this is happening?

EDIT: I've seen that the index from QuestionCheck is always 15, why this is happening?

Lechucico
  • 1,914
  • 7
  • 27
  • 60

3 Answers3

2

This is scoping issue. Once the event happens, i is already at questionList.Count which is out of the array range. And all of your QuestionCheck will be called with questionList.Count (15 in your case)

What you want to do is save i to a temporary value, and used that instead:

for (int i = 0; i < questionList.Count; i++)
{
    var currentIndex = i;
    GameObject child = Instantiate(questionButton, buttonLayout.transform);
    child.GetComponent<Text>().text = questionList[i].answer;
    child.GetComponent<Button>().onClick.AddListener(() => QuestionCheck(currentIndex ));
}
Lowkey
  • 836
  • 5
  • 12
2

The problem is that your onClick listener is not evaluated within the loop but afterwards when the button is clicked.

child.GetComponent<Button>().onClick.AddListener(() => QuestionCheck(i));

So while i equals 0,1,3...14 while the loop runs, when your button is eventually clicked the loop has long since finished and i equals 15.

An easy fix to the problem is to create another variable that will hold the current value of i.

for (int i = 0; i < questionList.Count; i++)
{
    int questionIndex = i;
    GameObject child = Instantiate(questionButton, buttonLayout.transform);
    child.GetComponent<Text>().text = questionList[questionIndex].answer;
    child.GetComponent<Button>().onClick.AddListener(() => QuestionCheck(questionIndex));
}
CaTs
  • 1,303
  • 10
  • 16
0

Argument out of range means in your case your list has 3 items, and its trying to access number 4, or 5 or anything higher than the range or count of your list.

also remember your list starts at 0, so your items are, 0,1, and 2

instead of

for (int i = 0; i < questionList.Count; i++)
{
    GameObject child = Instantiate(questionButton, buttonLayout.transform);
    child.GetComponent<Text>().text = questionList[i].answer;
    child.GetComponent<Button>().onClick.AddListener(() => QuestionCheck(i));
}

try

foreach(GameManager.Question q in questions){
    GameObject child = Instantiate(questionButton, buttonLayout.transform);
        child.GetComponent<Text>().text = q.answer;
        child.GetComponent<Button>().onClick.AddListener(() => QuestionCheck(i));
}
Technivorous
  • 1,682
  • 2
  • 16
  • 22