Quiz Game : Valid Question keep decreasing each time the game start.

Hi there I’m making a true false quiz game.
I have a problem regarding question index.
So there’s supposed to be 30 question stored for a level, and the 20 question appear randomly one by one. After answering the 20th question then the player win.

But here’s the problem. For example I start to try playing. The valid question is 30. Then I answer few question (for example 4). When I restart the game, the valid question is start from 26 instead of 30 again. Is there any way to fix it?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class QuestionsData : MonoBehaviour
{
    public Questions questions;

    [SerializeField]
    private Text _questionText;

    public GameObject completeLevelUI;

    void Start()
    {
        AskQuestion();
    }

    public void AskQuestion()
    {
        if (CountValidQuestions() == 10)
        {
            _questionText.text = string.Empty;
            ClearQuestion();
            CompleteLevel();
            return;
        }
        var randomIndex = 0;
        do
        {
            randomIndex = UnityEngine.Random.Range(0, questions.questionsList.Count);
        }
        while (questions.questionsList[randomIndex].questioned == true);

        questions.currentQuestion = randomIndex;
        questions.questionsList[questions.currentQuestion].questioned = true;
        _questionText.text = questions.questionsList[questions.currentQuestion].question;
    }

    public void ClearQuestion()
    {
        foreach (var question in questions.questionsList)
        {
           question.questioned = false;
        }
    }

    private int CountValidQuestions()
    {
        int validQuestions = 0;

        foreach (var question in questions.questionsList)
        {
            if (question.questioned == false)
                validQuestions++;
        }

        Debug.Log("Question Left " + validQuestions);
        return validQuestions;
    }

    public void CompleteLevel()
    {
        completeLevelUI.SetActive(true);
    }
}

When you mean restart, do you mean you:

  • Reload the Scene
  • Stop and Press Play in the Editor
  • Some other thing in a script

If you mean Stop and Press Play, you might be using a ScriptableObject for questions in this. If so, ScriptableObjects save data when you change them while running.

Yes I mean stop and press play on the editor. I use ScriptableObject on the script for storing the question. I already try and change it to MonoBehaviour but the problem still the same. [The one i show below is the one that not changed yet]

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

[CreateAssetMenu]
[System.Serializable]

public class Questions : ScriptableObject

{
    [System.Serializable]

    public class QuestionData
    {
        public string question = string.Empty;
        public bool isTrue = false;
        public bool questioned = false;
    }

    public int currentQuestion = 0;
    public List<QuestionData> questionsList;

    public void AddQuestion()
    {
        questionsList.Add(new QuestionData());
    }
}

I already try and change it to MonoBehaviour but the problem still the same.

Can I ask what exactly you did when you changed it to a MonoBehavior? The steps I envisioned are:

  • Changed to Questions : ScriptableObject
  • Created GameObject to hold Questions script
  • Set the Questions script values
  • Dragged Questions script into the collection
  • Pressed Play
  • Should reset values upon stopping and restarting

I also don’t even believe it should be a MonoBehavior, just a regular class that doesn’t derive from anything.

So I thought about this for a few minutes, but it’s probably in your best interest to leave it as a ScriptableObject, and instead cache the data in your QuestionsData class. So on Start() you would just do this.

private List<QuestionData> questionsCached;

void Start()
{
    questionsCached = questions.questionsList;
    AskQuestion(); // <== change everything to use questionsCached instead of questions
}

I was trying to make the Questions class just a regular class. But it affect the script I made to create the question storage. (I have a script using unity editor to manage the question storage easier).

I try this one but and it get error and said QuestionData could not be found
So I try using List<Questions.QuestionData> instead. It can be compiled but the problem still the same. Still not return to 30. Should I change something on the Questions class too?

You sure you changed everything in QuestionsData to be using questionsCached instead of questions? Nothing in QuestionsData except in your Start() should be referencing the old questions ScriptableObject.

Yes I mean set the questionsChached = questions.questionsList on void start right? isnt that mean when start, all questions.questionsList is questions instead of question? or should I literally change every questions to questionsCached in QuestionData? Let me show you the current QuestionData. Please tell me if something is not right.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class QuestionsData : MonoBehaviour
{
    public Questions questions;

    [SerializeField]
    private Text _questionText;

    public GameObject completeLevelUI;

    private List<Questions.QuestionData> questionsCached;

    void Start()
    {
        questionsCached = questions.questionsList;
        AskQuestion();
    }

    public void AskQuestion()
    {
        if (CountValidQuestions() == 10)
        {
            _questionText.text = string.Empty;
            ClearQuestion();
            CompleteLevel();
            return;
        }

        var randomIndex = 0;
        do
        {
            randomIndex = UnityEngine.Random.Range(0, questions.questionsList.Count);
        }
        while (questions.questionsList[randomIndex].questioned == true);

        questions.currentQuestion = randomIndex;
        questions.questionsList[questions.currentQuestion].questioned = true;
        _questionText.text = questions.questionsList[questions.currentQuestion].question;
    }

    public void ClearQuestion()
    {
        foreach (var question in questions.questionsList)
        {
           question.questioned = false;
        }
    }

    private int CountValidQuestions()
    {
        int validQuestions = 0;

        foreach (var question in questions.questionsList)
        {
            if (question.questioned == false)
                validQuestions++;
        }
    
        Debug.Log("Current Question :" + questions.currentQuestion);
        Debug.Log("Question Left " + validQuestions);
        return validQuestions;
    }

    public void CompleteLevel()
    {
        completeLevelUI.SetActive(true);
    }
}

or maybe you mean is should change this one (line 21 and 25) instead the one in QuestionData? or maybe both?

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

[CreateAssetMenu]
[System.Serializable]

public class Questions : ScriptableObject

{
    [System.Serializable]

    public class QuestionData
    {
        public string question = string.Empty;
        public bool isTrue = false;
        public bool questioned = false;
    }

    public int currentQuestion = 0;
    public List<QuestionData> questionsList;

    public void AddQuestion()
    {
        questionsList.Add(new QuestionData());
    }
}

The second part, to change all of them. Specifically, I mean replace questions.questionList with questionsCached. Don’t need to change the ScriptableObject. I’m going to sleep so hopefully someone else can pick up from where I left off if that doesn’t work.

If I change all questionsList to questionCached on Question class, is that mean I dont have to use questionsCached = questions.questionsList; on void Start at QuestionsData class?

I try changing every questionsList to questionsCached to the game but now the problem is :

and I notice all the question stored is disappear. I try to create a new question set but it there’s no way to add the question. It got completely blank.

Before :
7271044--878044--Before.PNG

After :
7271044--878041--After.PNG

No, you need both. We’re replacing your object’s array with a temporary one that we’re changing so that the true values don’t get updated.

Is it like this ? If its yes its till didn’t go back to 30 :frowning:

Questions Class :

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

[CreateAssetMenu]
[System.Serializable]

public class Questions : ScriptableObject

{
    [System.Serializable]

    public class QuestionData
    {
        public string question = string.Empty;
        public bool isTrue = false;
        public bool questioned = false;
    }

    public int currentQuestion = 0;
    public List<QuestionData> questionsCached;

    public void AddQuestion()
    {
        questionsCached.Add(new QuestionData());
    }
}

QuestionsData class :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class QuestionsData : MonoBehaviour
{
    public Questions questions;

    [SerializeField]
    private Text _questionText;

    public GameObject completeLevelUI;

    private List<Questions.QuestionData> questionsCached;

    void Start()
    {
        questionsCached = questions.questionsList;
        AskQuestion();
    }

    public void AskQuestion()
    {
        if (CountValidQuestions() == 10)
        {
            _questionText.text = string.Empty;
            ClearQuestion();
            CompleteLevel();
            return;
        }

        var randomIndex = 0;
        do
        {
            randomIndex = UnityEngine.Random.Range(0, questions.questionsList.Count);
        }
        while (questions.questionsList[randomIndex].questioned == true);

        questions.currentQuestion = randomIndex;
        questions.questionsList[questions.currentQuestion].questioned = true;
        _questionText.text = questions.questionsList[questions.currentQuestion].question;
    }

    public void ClearQuestion()
    {
        foreach (var question in questions.questionsList)
        {
           question.questioned = false;
        }
    }

    private int CountValidQuestions()
    {
        int validQuestions = 0;

        foreach (var question in questions.questionsList)
        {
            if (question.questioned == false)
                validQuestions++;
        }
       
        Debug.Log("Current Question :" + questions.currentQuestion);
        Debug.Log("Question Left " + validQuestions);
        return validQuestions;
    }

    public void CompleteLevel()
    {
        completeLevelUI.SetActive(true);
    }
}

How about using void reset tho?

like this

public class Example : ScriptableObject
{
    public GameObject target;

    void Reset()
    {
        //Output the message to the Console
        Debug.Log("Reset");
        if (!target)
            target = GameObject.FindWithTag("Player");
    }
}

I found it here Unity - Scripting API: ScriptableObject.Reset()
But I don’t know how to implement it to my code. I’m sorry I’m still very new at this. This is my first game actually. But it take months for me to get this far even tho its a very simple game.