Quiz Game 63. lecture

Hi there,
I am doing Quiz Game from the Unity 2d course and got into a problem that I cannot solve.
Here is the error:

NullReferenceException: Object reference not set to an instance of an object
Quiz.DisplayAnswers (System.Int32 index) (at Assets/Scripts/Quiz.cs:67)
Quiz.Update () (at Assets/Scripts/Quiz.cs:45)

And here is the code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using System.Xml.Serialization;

public class Quiz : MonoBehaviour
{
    [Header("Questions")]
    [SerializeField] TextMeshProUGUI questionText;
    [SerializeField] List<QuestionsSO> questions = new List<QuestionsSO>();
    QuestionsSO currentQuestion;

    [Header("Answers")]
    [SerializeField] GameObject[] answerButtons;
    int correctAnswerIndex;
    bool hasAnsweredEarly;

    [Header("Button colors")]
    [SerializeField] Sprite defaultAnswerSprite;
    [SerializeField] Sprite correctAnswerSprite;
    Image buttonImage;

    [Header("Timer")]
    [SerializeField] Image timerImage;
    Timer timer;
    
    // Start is called before the first frame update
    void Start()
    {
        timer = FindObjectOfType<Timer>();
    }
    private void Update()
    {
        timerImage.fillAmount = timer.fillFraction;
        if (timer.loadNewQuestion)
        {
            hasAnsweredEarly = false;
            GetNewQuestion();
            timer.loadNewQuestion = false;
        }
        else if(!hasAnsweredEarly && !timer.isAnsweringQuestion)
        {
            DisplayAnswers(-1);
            SetButtonState(false);
        }
    }
    void DisplayQuestion()
    {
        questionText.text = currentQuestion.getQuestion();
        for (int i = 0; i < answerButtons.Length; i++)
        {
            TextMeshProUGUI buttonText = answerButtons[i].GetComponentInChildren<TextMeshProUGUI>();
            buttonText.text = currentQuestion.GetAnswer(i);
        }
    }
    public void OnAnswerSelection(int index)
    {
        hasAnsweredEarly = true;
        DisplayAnswers(index);
        SetButtonState(false);
        timer.CancelTimer();
    }
    void DisplayAnswers(int index)
    {
        if (index == currentQuestion.GetCorrectAnswerIndex())
        {
            questionText.text = "Good!";
            buttonImage = answerButtons[index].GetComponent<Image>();
            buttonImage.sprite = correctAnswerSprite;
        }
        else
        {
            correctAnswerIndex = currentQuestion.GetCorrectAnswerIndex();
            questionText.text = "Bad, the correct answer is: \n " + currentQuestion.GetAnswer(correctAnswerIndex);
            buttonImage = answerButtons[correctAnswerIndex].GetComponent<Image>();
            buttonImage.sprite = correctAnswerSprite;
        }
    }
    void GetNewQuestion()
    {
        if (questions.Count > 0)
        {
            SetButtonState(true);
            SetDefaultButtonSprites();
            GetRandomQuestion();
            DisplayQuestion();
        }
      
    }

    void GetRandomQuestion()
    {
        int index = Random.Range(0, questions.Count);
        currentQuestion = questions[index];

        if (questions.Contains(currentQuestion))
        {
            questions.Remove(currentQuestion);
        }
    } 

    void SetButtonState(bool state)
    {
        for (int i = 0; i < answerButtons.Length; i++)
        {
            Button button = answerButtons[i].GetComponent<Button>();
            button.interactable = state;
        }
    }

    void SetDefaultButtonSprites()
    {
        for (int i = 0; i < answerButtons.Length; i++)
        {
            buttonImage = answerButtons[i].GetComponent<Image>();
            buttonImage.sprite = defaultAnswerSprite;
        }

    }

}





EDIT 27.10.2024
**So the actual solution I found there:

https://community.gamedev.tv/t/nullreferenceexception/218345?_gl=1*8bruk2*_ga*MTkxMjYzMzI5LjE2ODI1NDUxMjE.*_ga_2C81L26GR9*MTY4MzY1NDgyOS4yOC4xLjE2ODM2NTUwMzYuMC4wLjA.

I had to leave loadNewQuestion as null as in the course and with that I got rid of this bug and also only 1 question is being removed from the list at the beginning of the game.

Cheers

1 Like

Looks like currentQuestion has not been set. Does this happen as soon as the game starts? Could be that timer.loadNewQuestion is false, which will make the game immediately try to show answers for a question it has not asked yet. If that’s the case, set the initial value of loadNewQuestion in timer to true

2 Likes

Hi bixarrio. Thank you for your answer. Yes, this happens when I try to play the game and it started to happen since I made the changes to the code according to lecture 63. I tried your solution but it didn’t work. Here is the code for the Timer.cs. I am pretty newbie but it feels like reference to QuestionsSO is not working. Is it possible that Unity can glitch that way?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Timer : MonoBehaviour
{
    [SerializeField] float timeForAnswer = 7f;
    [SerializeField] float timeToShowCorrectAnswer = 3f;
    public bool isAnsweringQuestion = false;
    public bool loadNewQuestion = true;
    public float fillFraction;
    float timerValue;

    // Update is called once per frame
    void Update()
    {
        UpdateTimer();
        
    }

    public void CancelTimer()
    {
        timerValue = 0;
    }

    void UpdateTimer()
    {

        timerValue -= Time.deltaTime;
        if (isAnsweringQuestion)
        {
            if (timerValue > 0)
            {
                fillFraction = timerValue / timeForAnswer;
            }
            else
            {
                isAnsweringQuestion = false;
                timerValue = timeToShowCorrectAnswer;
            }
        }
        else
        {   
            if (timerValue > 0)
            {
                fillFraction = timerValue / timeToShowCorrectAnswer;
            }
            else
            {
                isAnsweringQuestion = true;
                loadNewQuestion = true;
                timerValue = timeForAnswer;
            }
        }

Please confirm the following

  • Do you have any questions in the list?
  • Do you possibly have another game object with a Quiz script on it, or perhaps 2 Quiz scripts on the same component?

Ok I got rid of this bug. Bixarrio you were right I had to change bool loadNewQuestion to true manually in the inspector as it didn’t changed it’s value through saving the code. Maybe can you explain to me why it sometimes happen?

However there is another bug that happen once I start the game. As I have 5 questions for now in this game when I start it and look in the inspector 2 questions are deleted from the list at the beginning. So the game actually shows 4 of 5 questions in total.

This is how things work in Unity. The value in the inspector is the one that will be used, even if you change the value in code later. This allows us to have the same script on multiple objects with different values. If I have two cars with a Movement script and I want one car to be faster than the other one, it wouldn’t be a good thing if the value in the code is the one that’s used because then my cars will have the same speed. If I set the speed in the inspector for each car, then those are the values each car will have.

I have seen this issue mentioned before. I don’t know what the fix is (I haven’t done this course) but you can search the forum and see if you can find an answer.
I think the reason it’s passing two questions is because Quiz is getting the question now (the fix you made) and then Timer sees the time is up and sets everything to get a new question. Try this;
In Timer, add the following code

void Awake()
{
    timerValue = timeForAnswer;
}

This should initialise the timer to the start of a question instead of the end (0). Let me know how that goes

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms