0
\$\begingroup\$

I am developing a Unity game which includes a multiple-choice quiz.

I've placed what I believe is a properly-formatted .json file (the quiz question, four answer choices, the correct answer, and an explanation for the answer) (which I checked with a .json formatter) in the StreamingAssets folder in the Unity project. I've created a custom class for the question, the four answer choices, the correct answer and the explanation of the answer.

I am trying to load the entire contents of the .json file into an array, "questions," then copy that array into another array, "questionsCopy." To avoid repeating questions, as a question is used during the gameplay, I will remove it (and its corresponding answer choices, correct answer and explanation) from the questionsCopy array. (I have not yet developed the GUI to show the question, answer choices and eventually the correct answer and its explanation.)

Here are relevant sections of what I've coded so far:

1) The custom class:

// This is the custom class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class QuestionChoicesAnswerHintExplanation : MonoBehaviour {

public string[] question; // An array of strings (rather than just a string) so that line spacing, which doesn't play well with .json, could be preserved
public string[] answerChoices;
public int correctAnswerIndex;
public string explanation;
}

2) From the GameController:

public QuestionChoicesAnswerExplanation[] questions; // This is the fixed size array of the questions, answer choices, answers, and explanations.
private static List<QuestionChoicesAnswerExplanation> questionsCopy; // This is the resizeable list (originally a copy of the array). The size of this list will diminish as we remove items after presenting each question.
private QuestionChoicesAnswerExplanation currentQuestion;

string path; // The path to the .json file storing the questions, answer choices, correct answer index, explanations.
string jsonString; // The contents of the .json file.

In the Start() in the GameController:

    path = Application.streamingAssetsPath + "/questionsAndAnswers.json";
    jsonString = File.ReadAllText(path);

    questions = JsonUtility.FromJson<QuestionChoicesAnswerExplanation[]>(jsonString);

    // Debug.LogWarning("Questions:");
    Debug.LogWarning(questions);

    if (questionsCopy == null || questionsCopy.Count == 0) // A list with zero elements isn't always null.
    {
        questionsCopy = questions.ToList<QuestionChoicesAnswerExplanation>();
    }

    PickRandomQuestion();

Further down in the GameController:

    public void PickRandomQuestion()
{
    int randomIndex = Random.Range(0, questionsCopy.Count);
    currentQuestion = questionsCopy[randomIndex];
    questionsCopy.RemoveAt(randomIndex);
}

3) Here are the contents of the .json file in the StreamingAssets folder:

{
"questions":

[

 {
 "question": ["Trinculo admits 'I have been in such a pickle...' in this comedy:"],
 "answerChoices": ["'The Tempest'", "'Henry 4, Part 1'", "'Henry 5'", "'The Merry Wives of Windsor'"],
 "correctAnswerIndex": 0,
 "explanation": "'Henry 4, Part 1,' and 'Henry 5, are both histories. To be in 'a pickle' usually means to be in a quandary. A broader view of this passage reveals Trinculo to be drunk: \n\nAlonso: \nAnd Trinculo is reeling ripe: where should they \nFind this grand liquor that hath gilded 'em? \nHow camest thou in this pickle? \n\nTrinculo: \nI have been in such a pickle since I \nsaw you last that, I fear me, will never out of \nmy bones: I shall not fear fly-blowing.' \n\n'The Tempest' 5.1."
 },
 {
 "question": ["In 'Hamlet,' this character remarks: 'Neither a borrower nor a lender be; \nFor loan oft loses both itself and friend, \nAnd borrowing dulls the edge of husbandry. \nThis above all: to thine own self be true,\nAnd it must follow, as the night the day,\nThou canst not then be false to any man:'"],
 "answerChoices": ["Fortinbras", "Gertrude", "Polonius", "The Ghost of Hamlet's Father"],
 "correctAnswerIndex": 2,
 "explanation": "The verbose Polonius is speaking to his son Laertes. 'Hamlet' 1.3."
 },
 {
 "question": ["Roger Daltrey, well into his career with The Who, played the roles for both Dromios, the twin servants, in a 1983 BBC production of:"],
 "answerChoices": ["'King John'", "'King Lear'", "'Coriolanus'", "'The Comedy of Errors'"],
 "correctAnswerIndex": 3,
 "explanation": "'The Comedy of Errors.'"
 }

 ]
}

BUT I'm getting an error:

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

Parameter name: index System.Collections.Generic.List`1[QuestionChoicesAnswerExplanation].get_Item (Int32 index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:633) GameController.PickRandomQuestion () (at Assets/Scripts/Managers/GameController.cs:741) GameController.Start () (at Assets/Scripts/Managers/GameController.cs:99)

The error message points to problems (GameController.cs:741 and GameController.cs:99), but I don't see what's wrong there. I am UNSURE about the message regarding line 633.

And the Debug.Logwarning yields this:

QuestionChoicesAnswerExplanation[] UnityEngine.Debug:LogWarning(Object) GameController:Start() (at Assets/Scripts/Managers/GameController.cs:92)

What need I do to fix this? Thank you.

\$\endgroup\$
  • \$\begingroup\$ This looks like it might be a new problem you should ask separately. It may be easier for users to follow that way. \$\endgroup\$ – DMGregory Jan 14 at 4:32
  • \$\begingroup\$ Thanks, DM. I hope to post the new problem separately in a day or two. \$\endgroup\$ – WPWPWP Jan 15 at 3:51
0
\$\begingroup\$

Your problem is similar to the one we discussed recently here - you're giving the JSON parser a different data type than you promised it.

This line:

questions = JsonUtility.FromJson<QuestionChoicesAnswerExplanation[]>(jsonString);

says "I promise the JSON text will be an array of question-choices-answer-explanation objects, something like..."

[    
 {
 "question": ["Trinculo admits 'I have been in such a pickle...' in this comedy:"],
 "answerChoices": ["'The Tempest'", "'Henry 4, Part 1'", "'Henry 5'", "'The Merry Wives of Windsor'"],
 "correctAnswerIndex": 0,
 "hint": "Hint: Trinculo is stranded on an island.",
 "explanation": "'Henry 4, Part 1,' and 'Henry 5, are both histories. To be in 'a pickle' usually means to be in a quandary. A broader view of this passage reveals Trinculo to be drunk: \n\nAlonso: \nAnd Trinculo is reeling ripe: where should they \nFind this grand liquor that hath gilded 'em? \nHow camest thou in this pickle? \n\nTrinculo: \nI have been in such a pickle since I \nsaw you last that, I fear me, will never out of \nmy bones: I shall not fear fly-blowing.' \n\n'The Tempest' 5.1."
 },
 {
 "question": ["In 'Hamlet,' this character remarks: 'Neither a borrower nor a lender be; \nFor loan oft loses both itself and friend, \nAnd borrowing dulls the edge of husbandry. \nThis above all: to thine own self be true,\nAnd it must follow, as the night the day,\nThou canst not then be false to any man:'"],
 "answerChoices": ["Fortinbras", "Gertrude", "Polonius", "The Ghost of Hamlet's Father"],
 "correctAnswerIndex": 2,
 "hint": "Hint: This character is very talkative.",
 "explanation": "The verbose Polonius is speaking to his son Laertes. 'Hamlet' 1.3."
 }
 ...
]

But that's not what you're giving it. Instead, you're giving it an object that contains an array of question-choices-answer-explanation objects:

{
    "questions":
      [
        ...
      ]
}

In C#, this type would look something like this:

[System.Serializable]
public class QuestionCollection {
    public QuestionChoicesAnswerExplanation[] questions;
}

Which means your parsing should look like...

questionCollection = JsonUtility.FromJson<QuestionCollection>(jsonString);
questions = questionCollection.questions;

Now you should get a non-empty array.

\$\endgroup\$
  • \$\begingroup\$ Thank you. I'll give that a try. I upvoted your answer but as I lack sufficient reputation, my upvote won't display yet. \$\endgroup\$ – WPWPWP Jan 5 at 3:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.