Search Unity

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

Discussion in 'Scripting' started by AmISquidward, Jun 25, 2021.

  1. AmISquidward

    AmISquidward

    Joined:
    May 20, 2021
    Posts:
    18
    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?

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public class QuestionsData : MonoBehaviour
    8. {
    9.     public Questions questions;
    10.  
    11.     [SerializeField]
    12.     private Text _questionText;
    13.  
    14.     public GameObject completeLevelUI;
    15.  
    16.     void Start()
    17.     {
    18.         AskQuestion();
    19.     }
    20.  
    21.     public void AskQuestion()
    22.     {
    23.         if (CountValidQuestions() == 10)
    24.         {
    25.             _questionText.text = string.Empty;
    26.             ClearQuestion();
    27.             CompleteLevel();
    28.             return;
    29.         }
    30.         var randomIndex = 0;
    31.         do
    32.         {
    33.             randomIndex = UnityEngine.Random.Range(0, questions.questionsList.Count);
    34.         }
    35.         while (questions.questionsList[randomIndex].questioned == true);
    36.  
    37.         questions.currentQuestion = randomIndex;
    38.         questions.questionsList[questions.currentQuestion].questioned = true;
    39.         _questionText.text = questions.questionsList[questions.currentQuestion].question;
    40.     }
    41.  
    42.     public void ClearQuestion()
    43.     {
    44.         foreach (var question in questions.questionsList)
    45.         {
    46.            question.questioned = false;
    47.         }
    48.     }
    49.  
    50.     private int CountValidQuestions()
    51.     {
    52.         int validQuestions = 0;
    53.  
    54.         foreach (var question in questions.questionsList)
    55.         {
    56.             if (question.questioned == false)
    57.                 validQuestions++;
    58.         }
    59.  
    60.         Debug.Log("Question Left " + validQuestions);
    61.         return validQuestions;
    62.     }
    63.  
    64.     public void CompleteLevel()
    65.     {
    66.         completeLevelUI.SetActive(true);
    67.     }
    68. }
    69.  
     
  2. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    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.
     
  3. AmISquidward

    AmISquidward

    Joined:
    May 20, 2021
    Posts:
    18
    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]

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [CreateAssetMenu]
    6. [System.Serializable]
    7.  
    8. public class Questions : ScriptableObject
    9.  
    10. {
    11.     [System.Serializable]
    12.  
    13.     public class QuestionData
    14.     {
    15.         public string question = string.Empty;
    16.         public bool isTrue = false;
    17.         public bool questioned = false;
    18.     }
    19.  
    20.     public int currentQuestion = 0;
    21.     public List<QuestionData> questionsList;
    22.  
    23.     public void AddQuestion()
    24.     {
    25.         questionsList.Add(new QuestionData());
    26.     }
    27. }
    I already try and change it to MonoBehaviour but the problem still the same.
     
    Last edited: Jun 25, 2021
  4. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    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.
     
  5. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    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.

    Code (CSharp):
    1. private List<QuestionData> questionsCached;
    2.  
    3. void Start()
    4. {
    5.     questionsCached = questions.questionsList;
    6.     AskQuestion(); // <== change everything to use questionsCached instead of questions
    7. }
     
  6. AmISquidward

    AmISquidward

    Joined:
    May 20, 2021
    Posts:
    18
    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?
     
  7. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    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.
     
  8. AmISquidward

    AmISquidward

    Joined:
    May 20, 2021
    Posts:
    18
    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.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public class QuestionsData : MonoBehaviour
    8. {
    9.     public Questions questions;
    10.  
    11.     [SerializeField]
    12.     private Text _questionText;
    13.  
    14.     public GameObject completeLevelUI;
    15.  
    16.     private List<Questions.QuestionData> questionsCached;
    17.  
    18.     void Start()
    19.     {
    20.         questionsCached = questions.questionsList;
    21.         AskQuestion();
    22.     }
    23.  
    24.     public void AskQuestion()
    25.     {
    26.         if (CountValidQuestions() == 10)
    27.         {
    28.             _questionText.text = string.Empty;
    29.             ClearQuestion();
    30.             CompleteLevel();
    31.             return;
    32.         }
    33.  
    34.         var randomIndex = 0;
    35.         do
    36.         {
    37.             randomIndex = UnityEngine.Random.Range(0, questions.questionsList.Count);
    38.         }
    39.         while (questions.questionsList[randomIndex].questioned == true);
    40.  
    41.         questions.currentQuestion = randomIndex;
    42.         questions.questionsList[questions.currentQuestion].questioned = true;
    43.         _questionText.text = questions.questionsList[questions.currentQuestion].question;
    44.     }
    45.  
    46.     public void ClearQuestion()
    47.     {
    48.         foreach (var question in questions.questionsList)
    49.         {
    50.            question.questioned = false;
    51.         }
    52.     }
    53.  
    54.     private int CountValidQuestions()
    55.     {
    56.         int validQuestions = 0;
    57.  
    58.         foreach (var question in questions.questionsList)
    59.         {
    60.             if (question.questioned == false)
    61.                 validQuestions++;
    62.         }
    63.    
    64.         Debug.Log("Current Question :" + questions.currentQuestion);
    65.         Debug.Log("Question Left " + validQuestions);
    66.         return validQuestions;
    67.     }
    68.  
    69.     public void CompleteLevel()
    70.     {
    71.         completeLevelUI.SetActive(true);
    72.     }
    73. }
    74.  
    or maybe you mean is should change this one (line 21 and 25) instead the one in QuestionData? or maybe both?

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [CreateAssetMenu]
    6. [System.Serializable]
    7.  
    8. public class Questions : ScriptableObject
    9.  
    10. {
    11.     [System.Serializable]
    12.  
    13.     public class QuestionData
    14.     {
    15.         public string question = string.Empty;
    16.         public bool isTrue = false;
    17.         public bool questioned = false;
    18.     }
    19.  
    20.     public int currentQuestion = 0;
    21.     public List<QuestionData> questionsList;
    22.  
    23.     public void AddQuestion()
    24.     {
    25.         questionsList.Add(new QuestionData());
    26.     }
    27. }
     
    Last edited: Jun 25, 2021
  9. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    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.
     
  10. AmISquidward

    AmISquidward

    Joined:
    May 20, 2021
    Posts:
    18
    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 :
    Before.PNG

    After :
    After.PNG
     
    Last edited: Jun 25, 2021
  11. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,647
    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.
     
  12. AmISquidward

    AmISquidward

    Joined:
    May 20, 2021
    Posts:
    18
    Is it like this ? If its yes its till didn't go back to 30 :(

    Questions Class :
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [CreateAssetMenu]
    6. [System.Serializable]
    7.  
    8. public class Questions : ScriptableObject
    9.  
    10. {
    11.     [System.Serializable]
    12.  
    13.     public class QuestionData
    14.     {
    15.         public string question = string.Empty;
    16.         public bool isTrue = false;
    17.         public bool questioned = false;
    18.     }
    19.  
    20.     public int currentQuestion = 0;
    21.     public List<QuestionData> questionsCached;
    22.  
    23.     public void AddQuestion()
    24.     {
    25.         questionsCached.Add(new QuestionData());
    26.     }
    27. }
    QuestionsData class :
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public class QuestionsData : MonoBehaviour
    8. {
    9.     public Questions questions;
    10.  
    11.     [SerializeField]
    12.     private Text _questionText;
    13.  
    14.     public GameObject completeLevelUI;
    15.  
    16.     private List<Questions.QuestionData> questionsCached;
    17.  
    18.     void Start()
    19.     {
    20.         questionsCached = questions.questionsList;
    21.         AskQuestion();
    22.     }
    23.  
    24.     public void AskQuestion()
    25.     {
    26.         if (CountValidQuestions() == 10)
    27.         {
    28.             _questionText.text = string.Empty;
    29.             ClearQuestion();
    30.             CompleteLevel();
    31.             return;
    32.         }
    33.  
    34.         var randomIndex = 0;
    35.         do
    36.         {
    37.             randomIndex = UnityEngine.Random.Range(0, questions.questionsList.Count);
    38.         }
    39.         while (questions.questionsList[randomIndex].questioned == true);
    40.  
    41.         questions.currentQuestion = randomIndex;
    42.         questions.questionsList[questions.currentQuestion].questioned = true;
    43.         _questionText.text = questions.questionsList[questions.currentQuestion].question;
    44.     }
    45.  
    46.     public void ClearQuestion()
    47.     {
    48.         foreach (var question in questions.questionsList)
    49.         {
    50.            question.questioned = false;
    51.         }
    52.     }
    53.  
    54.     private int CountValidQuestions()
    55.     {
    56.         int validQuestions = 0;
    57.  
    58.         foreach (var question in questions.questionsList)
    59.         {
    60.             if (question.questioned == false)
    61.                 validQuestions++;
    62.         }
    63.        
    64.         Debug.Log("Current Question :" + questions.currentQuestion);
    65.         Debug.Log("Question Left " + validQuestions);
    66.         return validQuestions;
    67.     }
    68.  
    69.     public void CompleteLevel()
    70.     {
    71.         completeLevelUI.SetActive(true);
    72.     }
    73. }
    74.  
     
  13. AmISquidward

    AmISquidward

    Joined:
    May 20, 2021
    Posts:
    18
    How about using void reset tho?

    like this

    Code (CSharp):
    1. public class Example : ScriptableObject
    2. {
    3.     public GameObject target;
    4.  
    5.     void Reset()
    6.     {
    7.         //Output the message to the Console
    8.         Debug.Log("Reset");
    9.         if (!target)
    10.             target = GameObject.FindWithTag("Player");
    11.     }
    12. }
    I found it here https://docs.unity3d.com/2020.1/Documentation/ScriptReference/ScriptableObject.Reset.html
    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.