Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Quiz Game tutorial question

Discussion in 'Community Learning & Teaching' started by kimi81, Jan 16, 2017.

  1. kimi81

    kimi81

    Joined:
    Feb 28, 2015
    Posts:
    6
    How to randomize non-repaeting question?
    Hi, I`m making a quiz game following official live training tutorial and I would like to set it up so that the questions are showing up randomly in that way that they are not repeating in the currentRound of quiz. I saw in comments of that tutorial that author said we could use Shuffle bag technique but that is a little bit too complicated to implement. Is there any other simpler way to do it? Here`s a script from that tutorial that contains ShowQuestion method:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.SceneManagement;
    4. using System.Collections.Generic;
    5.  
    6. public class GameController : MonoBehaviour
    7. {
    8.     public SimpleObjectPool answerButtonObjectPool;
    9.     public Text questionText;
    10.     public Text scoreDisplay;
    11.     public Text timeRemainingDisplay;
    12.     public Transform answerButtonParent;
    13.  
    14.     public GameObject questionDisplay;
    15.     public GameObject roundEndDisplay;
    16.     public Text highScoreDisplay;
    17.  
    18.     private DataController dataController;
    19.     private RoundData currentRoundData;
    20.     private QuestionData[] questionPool;
    21.  
    22.     private bool isRoundActive = false;
    23.     private float timeRemaining;
    24.     private int playerScore;
    25.     private int questionIndex;
    26.     private List<GameObject> answerButtonGameObjects = new List<GameObject>();
    27.  
    28.     void Start()
    29.     {
    30.         dataController = FindObjectOfType<DataController>();                                // Store a reference to the DataController so we can request the data we need for this round
    31.  
    32.         currentRoundData = dataController.GetCurrentRoundData();                            // Ask the DataController for the data for the current round. At the moment, we only have one round - but we could extend this
    33.         questionPool = currentRoundData.questions;                                            // Take a copy of the questions so we could shuffle the pool or drop questions from it without affecting the original RoundData object
    34.  
    35.         timeRemaining = currentRoundData.timeLimitInSeconds;                                // Set the time limit for this round based on the RoundData object
    36.         UpdateTimeRemainingDisplay();
    37.         playerScore = 0;
    38.         questionIndex = 0;
    39.  
    40.         ShowQuestion();
    41.         isRoundActive = true;
    42.     }
    43.  
    44.     void Update()
    45.     {
    46.         if (isRoundActive)
    47.         {
    48.             timeRemaining -= Time.deltaTime;                                                // If the round is active, subtract the time since Update() was last called from timeRemaining
    49.             UpdateTimeRemainingDisplay();
    50.  
    51.             if (timeRemaining <= 0f)                                                        // If timeRemaining is 0 or less, the round ends
    52.             {
    53.                 EndRound();
    54.             }
    55.         }
    56.     }
    57.  
    58.     void ShowQuestion()
    59.     {
    60.         RemoveAnswerButtons();
    61.  
    62.         QuestionData questionData = questionPool[questionIndex];                            // Get the QuestionData for the current question
    63.         questionText.text = questionData.questionText;                                        // Update questionText with the correct text
    64.  
    65.         for (int i = 0; i < questionData.answers.Length; i ++)                                // For every AnswerData in the current QuestionData...
    66.         {
    67.             GameObject answerButtonGameObject = answerButtonObjectPool.GetObject();            // Spawn an AnswerButton from the object pool
    68.             answerButtonGameObjects.Add(answerButtonGameObject);
    69.             answerButtonGameObject.transform.SetParent(answerButtonParent);
    70.             answerButtonGameObject.transform.localScale = Vector3.one;
    71.  
    72.             AnswerButton answerButton = answerButtonGameObject.GetComponent<AnswerButton>();
    73.             answerButton.SetUp(questionData.answers[i]);                                    // Pass the AnswerData to the AnswerButton so the AnswerButton knows what text to display and whether it is the correct answer
    74.         }
    75.     }
    76.  
    77.     void RemoveAnswerButtons()
    78.     {
    79.         while (answerButtonGameObjects.Count > 0)                                            // Return all spawned AnswerButtons to the object pool
    80.         {
    81.             answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
    82.             answerButtonGameObjects.RemoveAt(0);
    83.         }
    84.     }
    85.  
    86.     public void AnswerButtonClicked(bool isCorrect)
    87.     {
    88.         if (isCorrect)
    89.         {
    90.             playerScore += currentRoundData.pointsAddedForCorrectAnswer;                    // If the AnswerButton that was clicked was the correct answer, add points
    91.             scoreDisplay.text = playerScore.ToString();
    92.         }
    93.  
    94.         if(questionPool.Length > questionIndex + 1)                                            // If there are more questions, show the next question
    95.         {
    96.             questionIndex++;
    97.             ShowQuestion();
    98.         }
    99.         else                                                                                // If there are no more questions, the round ends
    100.         {
    101.             EndRound();
    102.         }
    103.     }
    104.  
    105.     private void UpdateTimeRemainingDisplay()
    106.     {
    107.         timeRemainingDisplay.text = Mathf.Round(timeRemaining).ToString();
    108.     }
    109.  
    110.     public void EndRound()
    111.     {
    112.         isRoundActive = false;
    113.  
    114.         questionDisplay.SetActive(false);
    115.         roundEndDisplay.SetActive(true);
    116.     }
    117.  
    118.     public void ReturnToMenu()
    119.     {
    120.         SceneManager.LoadScene("MenuScreen");
    121.     }
    122. }
     
  2. lathster

    lathster

    Joined:
    Dec 14, 2012
    Posts:
    15
    You could try adding a new List<int> called something like questionIndexesChosen which keeps track of which questionIndex have come before.
    Then add a new method:
    Code (CSharp):
    1.  
    2. void ChooseQuestion()
    3. {
    4.      bool questionChosen = false;
    5.    
    6.      while(questionChosen != true) // While question chosen does not equal true
    7.      {
    8.            int random = Random.Range(0, questionPool.Length); // Choose a random number between 0 and the questionPool length
    9.  
    10.            if (!questionIndexesChosen.Contains(random)) // If the new list doesn't contain the number
    11.            {
    12.                 questionIndexesChosen.Add(random); // Add the number to the list
    13.                 questionIndex = random; // Set the questionIndex to the number
    14.                 questionChosen = true; // Set questionChosen to true to end the while loop
    15.            }
    16.       }
    17.  
    18. }
    Then either call this method before ShowQuestion() or at the start of the ShowQuestion() method.

    That should work but I haven't actually tested it :)
     
  3. Millemuz

    Millemuz

    Joined:
    Jan 27, 2017
    Posts:
    4
    This almost works.
    It now chooses a random question from the list of questions (in my case 5 questions). But when it choose question 5 in the list, the quiz ends. So if it starts with question 5 and it is answered the round ends, and there was only one question in the round. The problem lies in this part in the questionsIndex since the last question in the array always will make questionIndex bigger than questionPool.

    Code (CSharp):
    1.  
    2. public void AnswerButtonClicked(bool isCorrect)
    3.     {
    4.         if (isCorrect)
    5.         {
    6.             playerScore += currentRoundData.pointsAddedForCorrectAnswer;                    // If the AnswerButton that was clicked was the correct answer, add points
    7.             scoreDisplay.text = playerScore.ToString();
    8.         }
    9.         if(questionPool.Length > questionIndex + 1)                                            // If there are more questions, show the next question
    10.         {
    11.             questionIndex++;
    12.             ShowQuestion();
    13.         }
    14.         else                                                                                // If there are no more questions, the round ends
    15.         {
    16.             EndRound();
    17.         }
    18.     }
     
    Last edited: Feb 1, 2017
    lathster likes this.
  4. lathster

    lathster

    Joined:
    Dec 14, 2012
    Posts:
    15
    In which case add a new int called something like qNumber. Set qNumber to 0 then change the code to:

    Code (CSharp):
    1. public void AnswerButtonClicked(bool isCorrect)
    2.     {
    3.         if (isCorrect)
    4.         {
    5.             playerScore += currentRoundData.pointsAddedForCorrectAnswer;                    // If the AnswerButton that was clicked was the correct answer, add points
    6.             scoreDisplay.text = playerScore.ToString();
    7.         }
    8.         if(qNumber < questionPool.Length - 1)                                            // If there are more questions, show the next question
    9.         {
    10.             qNumber++;
    11.             ShowQuestion();
    12.         }
    13.         else                                                                                // If there are no more questions, the round ends
    14.         {
    15.             EndRound();
    16.         }
    17.     }
    That should fix the problem because the game is no longer tracking the questionIndex but the actual number of questions asked
     
    Last edited: Jul 12, 2017
  5. Millemuz

    Millemuz

    Joined:
    Jan 27, 2017
    Posts:
    4
    I should have seen that.
    You are my hero good sir :)
     
    lathster likes this.
  6. n0vember04

    n0vember04

    Joined:
    Mar 2, 2017
    Posts:
    2
    To millemuz:

    Can I see your final coding about this project?.. My game is same as yours, i follow your codes regarding with the random questioning but it doesn't work with my project. The question hasn't change. It just repeating the first question until the game's over. Please :) Thank You!..
     
  7. Millemuz

    Millemuz

    Joined:
    Jan 27, 2017
    Posts:
    4
    Here is my code
    I'm sorry its a bit messy it's still a work in progress, but i've tried cleaning it up a bit. I hope you can read it.


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4. using UnityEngine.SceneManagement;
    5. using System.Collections.Generic;
    6.  
    7.  
    8. public class GameController : MonoBehaviour
    9. {
    10.  
    11.     public Text questionDisplayText;
    12.     public Text imageQuestionDisplayText;
    13.     public Text scoreDisplayText;
    14.     public Text scoreDisplayRoundOverText;
    15.     public Text timeRemainingDisplayText;
    16.  
    17.     public SimpleObjectPool answerButtonObjectPool;
    18.  
    19.     public Transform answerButtonParent;
    20.  
    21.     public GameObject questionDisplay;
    22.     public GameObject roundEndDisplay;
    23.     public GameObject correctAnswerPanel;
    24.     public GameObject falseAnswerPanel;
    25.     public GameObject imagePanel;
    26.     public GameObject imageQuestionDisplay;
    27.  
    28.     public AudioSource AudioSource;
    29.     public Image ImageQuestion;
    30.  
    31.     private DataController dataController;
    32.     private RoundData currentRoundData;
    33.     private QuestionData[] questionPool;
    34.  
    35.     private bool isRoundActive;
    36.  
    37.     private float timeRemaining;
    38.     private int questionIndex;
    39.     private float playerScore;
    40.     private float score1;
    41.     private float score2;
    42.     private int qNumber = 0;
    43.  
    44.     private List<GameObject> answerButtonGameObjects = new List<GameObject>();
    45.     private List<int> questionIndexesChosen = new List<int>();
    46.  
    47.     [SerializeField]
    48.     private float timeBetweenQuestions;
    49.  
    50.  
    51.     // Use this for initialization
    52.     void Start()
    53.     {
    54.         dataController = FindObjectOfType<DataController>();
    55.         currentRoundData = dataController.GetCurrentRoundData();
    56.         questionPool = currentRoundData.questions;
    57.         timeRemaining = currentRoundData.timeLimitInSeconds;
    58.      
    59.         UpdateTimeRemainingDisplay();
    60.        
    61.         playerScore = 0;
    62.      
    63.         questionIndex = 0;
    64.  
    65.         ShowQuestion();
    66.         QuestionData questionData = questionPool[questionIndex];
    67.         AudioSource.clip = questionData.QuestionAudio;
    68.         AudioSource.Play();
    69.      
    70.         isRoundActive = true;
    71.        
    72.     }
    73.  
    74.     private void ShowQuestion()
    75.     {
    76.        
    77.        
    78.         RemoveAnswerButtons();
    79.        
    80. //Choose question is here!
    81.         ChooseQuestion();
    82.         QuestionData questionData = questionPool[questionIndex];
    83.         ImageQuestion.sprite = questionData.QuestionImage2;
    84.         if (ImageQuestion.sprite != null)
    85.         {
    86.             imagePanel.SetActive(true);
    87.             questionDisplay.SetActive(false);
    88.              imageQuestionDisplay.SetActive(true);
    89.          }
    90.         else
    91.         {
    92.             imagePanel.SetActive(false);
    93.             imageQuestionDisplay.SetActive(false);
    94.             questionDisplay.SetActive(true);
    95.            
    96.          
    97.         }
    98.        
    99.         for (int i = 0; i < questionData.answers.Length; i++)
    100.         {
    101.             GameObject answerButtonGameObject = answerButtonObjectPool.GetObject();
    102.             answerButtonGameObjects.Add(answerButtonGameObject);
    103.             answerButtonGameObject.transform.SetParent(answerButtonParent);
    104.            
    105.                         AnswerButton answerButton = answerButtonGameObject.GetComponent<AnswerButton>();
    106.             answerButton.Setup(questionData.answers[i]);
    107.         }
    108.  
    109.         questionDisplayText.text = questionData.questionText;
    110.         imageQuestionDisplayText.text = questionData.questionText;
    111.     }
    112.    
    113.  
    114.     void ChooseQuestion()
    115.     {
    116.         bool questionChosen = false;
    117.  
    118.         while (questionChosen != true) // While question chosen does not equal true
    119.         {
    120.        
    121.             int random = Random.Range(0, questionPool.Length); // Choose a random number between 0 and the questionPool length
    122.  
    123.             if (!questionIndexesChosen.Contains(random)) // If the new list doesn't contain the number
    124.             {
    125.                 questionIndexesChosen.Add(random); // Add the number to the list
    126.                 questionIndex = random; // Set the questionIndex to the number
    127.                 questionChosen = true; // Set questionChosen to true to end the while loop
    128.             }
    129.         }
    130.        
    131.     }
    132.  
    133.    
    134.     private void RemoveAnswerButtons()
    135.     {
    136.         while (answerButtonGameObjects.Count > 0)
    137.         {
    138.             answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
    139.             answerButtonGameObjects.RemoveAt(0);
    140.         }
    141.     }
    142.  
    143.     public void AnswerButtonClicked(bool isCorrect)
    144.     {
    145.         if (isCorrect)
    146.         {
    147.             score1 = timeRemaining -= Time.deltaTime;
    148.             score2 = score1 * 10;
    149.             playerScore += score2;
    150.            
    151.             scoreDisplayText.text = "Score: " + playerScore.ToString("F0");
    152.             scoreDisplayRoundOverText.text = "Score: " + playerScore.ToString("F0");
    153.            
    154.             correctAnswerPanel.SetActive(true);
    155.             questionDisplay.SetActive(false);
    156.             StartCoroutine(TimeBetweenQuestions());
    157.            
    158.            
    159.         }
    160.         else
    161.         {
    162.             falseAnswerPanel.SetActive(true);
    163.             questionDisplay.SetActive(false);
    164.             StartCoroutine(TimeBetweenQuestions());
    165.                        
    166.         }
    167.        
    168.         if (qNumber + 1 < questionPool.Length)                                          
    169.         {
    170.             qNumber++;
    171.             ShowQuestion();
    172.            
    173.         }
    174.         else
    175.         {
    176.             EndRound();
    177.         }
    178.  
    179.     }
    180.  
    181.     public void EndRound()
    182.     {
    183.         isRoundActive = false;
    184.  
    185.         questionDisplay.SetActive(false);
    186.         roundEndDisplay.SetActive(true);
    187.     }
    188.  
    189.     public void ReturnToMenu()
    190.     {
    191.         SceneManager.LoadScene("MenuScreen");
    192.     }
    193.  
    194.    
    195.  
    196.     IEnumerator TimeBetweenQuestions()
    197.     {
    198.        
    199.         yield return new WaitForSeconds(timeBetweenQuestions);
    200.                
    201.         correctAnswerPanel.SetActive(false);
    202.         falseAnswerPanel.SetActive(false);
    203.         timeRemaining = 10;
    204.         QuestionData questionData = questionPool[questionIndex];
    205.         AudioSource.clip = questionData.QuestionAudio;
    206.         AudioSource.Play();
    207.  
    208.         }
    209.  
    210.     private void UpdateTimeRemainingDisplay()
    211.     {
    212.         timeRemainingDisplayText.text = Mathf.Round(timeRemaining).ToString();
    213.     }
    214.  
    215.     // Update is called once per frame
    216.     void Update()
    217.     {
    218.         if (isRoundActive)
    219.         {
    220.             timeRemaining -= Time.deltaTime;
    221.             UpdateTimeRemainingDisplay();
    222.  
    223.             if (timeRemaining <= 0f)
    224.             {
    225.                 Debug.Log("Time is up!!");
    226.                 qNumber++;
    227.                 ShowQuestion();
    228.              
    229.                 timeRemaining = 10;
    230.                
    231.             }
    232.  
    233.         }
    234.     }
    235. }
     
  8. n0vember04

    n0vember04

    Joined:
    Mar 2, 2017
    Posts:
    2
    To Millemuz:
    I manage to read your work Sir and it's fine. By the way, thank you for this and to your effort. It's now working, it already choose a random questions. I just missed a little codes hehehe. I am now prepared for the defense this coming Monday.. Thank You again sir..
     
    Millemuz likes this.
  9. mikethingsbetter

    mikethingsbetter

    Joined:
    Jan 17, 2017
    Posts:
    1
    Hi Millemuz,
    Thanks for sharing your code, I was able to work out how to randomly generate my questions.
    One thing though. Did you have the issue that the last question in your hierarchy is asked before the last question it ends the game?
     
  10. tisbrat

    tisbrat

    Joined:
    Nov 20, 2017
    Posts:
    2
    To: mikethingsbetter and n0vember04

    Were you able to figure out how to randomize the questions from the original code? And do you mind sharing your project if it's completed?
     
  11. siaknimarkanthony

    siaknimarkanthony

    Joined:
    Nov 28, 2017
    Posts:
    4
    hey man how did you mange this scrip >> public GameObject imageQuestionDisplay; did it worked in the array of question?
     
  12. onurozel

    onurozel

    Joined:
    Mar 6, 2018
    Posts:
    2
    Hi everyone,
    Especially Millemuz!!!
    I write some codes about quiz game like yours for random question and this codes work but I have a problem about player score...
    Please can you help me...
    MY CODES ARE BELOW...Please examine that and feedback me
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.SceneManagement;
    4. using System.Collections.Generic;
    5.  
    6. public class GameController : MonoBehaviour
    7. {
    8.     public SimpleObjectPool answerButtonObjectPool;
    9.     public Text questionText;
    10.     public Text scoreDisplay;
    11.     public Text timeRemainingDisplay;
    12.     public Transform answerButtonParent;
    13.  
    14.     public GameObject questionDisplay;
    15.     public GameObject roundEndDisplay;
    16.     public Text highScoreDisplay;
    17.  
    18.     private DataController dataController;
    19.     private RoundData currentRoundData;
    20.     private QuestionData[] questionPool;
    21.  
    22.     private bool isRoundActive = false;
    23.     private float timeRemaining;
    24.     private int playerScore;
    25.     private int questionIndex;
    26.     private int qNumber=0;
    27.  
    28.     private List<GameObject> answerButtonGameObjects = new List<GameObject>();
    29.     private List<int> questionIndexesChosen=new List<int>();
    30.  
    31.     void Start()
    32.     {
    33.         dataController = FindObjectOfType<DataController>();                                // Store a reference to the DataController so we can request the data we need for this round
    34.  
    35.         currentRoundData = dataController.GetCurrentRoundData();                            // Ask the DataController for the data for the current round. At the moment, we only have one round - but we could extend this
    36.         questionPool = currentRoundData.questions;                                            // Take a copy of the questions so we could shuffle the pool or drop questions from it without affecting the original RoundData object
    37.  
    38.         timeRemaining = currentRoundData.timeLimitInSeconds;                                // Set the time limit for this round based on the RoundData object
    39.         UpdateTimeRemainingDisplay();
    40.         playerScore = 0;
    41.         questionIndex = 0;
    42.         ShowQuestion();
    43.         isRoundActive = true;
    44.     }
    45.  
    46.     void Update()
    47.     {
    48.         if (isRoundActive)
    49.         {
    50.             timeRemaining -= Time.deltaTime;                                                // If the round is active, subtract the time since Update() was last called from timeRemaining
    51.             UpdateTimeRemainingDisplay();
    52.  
    53.             if (timeRemaining <= 0f)                                                        // If timeRemaining is 0 or less, the round ends
    54.             {
    55.                 qNumber++;
    56.                 ShowQuestion ();
    57.             }
    58.         }
    59.     }
    60.     void ChooseQuestion()
    61.     {
    62.  
    63.         bool questionChoosen = false;
    64.  
    65.         while (questionChoosen != true) {
    66.        
    67.             int random = Random.Range (0, questionPool.Length);
    68.  
    69.  
    70.             if (!questionIndexesChosen.Contains(random)) {
    71.            
    72.                 questionIndexesChosen.Add (random);
    73.                 questionIndex = random;
    74.                 questionChoosen = true;
    75.            
    76.             }
    77.        
    78.         }
    79.  
    80.     }
    81.     void ShowQuestion()
    82.     {
    83.         RemoveAnswerButtons();
    84.         ChooseQuestion ();
    85.         QuestionData questionData = questionPool[questionIndex];                            // Get the QuestionData for the current question
    86.         questionText.text = questionData.questionText;                                        // Update questionText with the correct text
    87.  
    88.         for (int i = 0; i < questionData.answers.Length; i ++)                                // For every AnswerData in the current QuestionData...
    89.         {
    90.             GameObject answerButtonGameObject = answerButtonObjectPool.GetObject();            // Spawn an AnswerButton from the object pool
    91.             answerButtonGameObjects.Add(answerButtonGameObject);
    92.             answerButtonGameObject.transform.SetParent(answerButtonParent);
    93.             answerButtonGameObject.transform.localScale = Vector3.one;
    94.  
    95.             AnswerButton answerButton = answerButtonGameObject.GetComponent<AnswerButton>();
    96.             answerButton.Setup(questionData.answers[i]);                                    // Pass the AnswerData to the AnswerButton so the AnswerButton knows what text to display and whether it is the correct answer
    97.         }
    98.     }
    99.  
    100.     void RemoveAnswerButtons()
    101.     {
    102.         while (answerButtonGameObjects.Count > 0)                                            // Return all spawned AnswerButtons to the object pool
    103.         {
    104.             answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
    105.             answerButtonGameObjects.RemoveAt(0);
    106.         }
    107.     }
    108.  
    109.     public void AnswerButtonClicked(bool isCorrect)
    110.     {
    111.         if(qNumber<questionPool.Length-1)                                            // If there are more questions, show the next question
    112.         {
    113.             qNumber++;
    114.  
    115.             ShowQuestion();
    116.         }
    117.         else                                                                                // If there are no more questions, the round ends
    118.         {
    119.             EndRound();
    120.         }
    121.  
    122.         if (isCorrect)
    123.         {
    124.             playerScore += currentRoundData.pointsAddedForCorrectAnswers;                    // If the AnswerButton that was clicked was the correct answer, add points
    125.             scoreDisplay.text = "Score:"+playerScore.ToString();
    126.         }
    127.  
    128.  
    129.     }
    130.  
    131.     private void UpdateTimeRemainingDisplay()
    132.     {
    133.         timeRemainingDisplay.text = "Time :"+Mathf.Round(timeRemaining).ToString();
    134.     }
    135.  
    136.     public void EndRound()
    137.     {
    138.         isRoundActive = false;
    139.         dataController.SubmitNewPlayerScore (playerScore);
    140.         highScoreDisplay.text = "Highscore\n"+dataController.GetHighestPlayerScore ().ToString ();
    141.  
    142.         questionDisplay.SetActive(false);
    143.         roundEndDisplay.SetActive(true);
    144.     }
    145.  
    146.     public void ReturnToMenu()
    147.     {
    148.         SceneManager.LoadScene("MenuScreen");
    149.     }
    150. }
     
  13. thejrz12

    thejrz12

    Joined:
    Aug 19, 2018
    Posts:
    1
    Have you tried to add levels? I'ts so confusing when adding levels sigh.