Non Repeating Random

I am having problems with my script as I lack the skills to code in c#. I can seem to make my random question only appear once. Can you guys please help me? This is my code:

void ShowQuestion()
    {
        RemoveAnswerButtons();

        QuestionData questionData = questionPool[questionIndex];                          
        questionText.text = questionData.questionText;                                     
     

        for (int i = 0; i < questionData.answers.Length; i++)                              
        {
       

            GameObject answerButtonGameObject = answerButtonObjectPool.GetObject();
            answerButtonGameObjects.Add(answerButtonGameObject);
            answerButtonGameObject.transform.SetParent(answerButtonParent);
            answerButtonGameObject.transform.localScale = Vector3.one;

            AnswerButton answerButton = answerButtonGameObject.GetComponent<AnswerButton>();
            answerButton.SetUp(questionData.answers[i]);                                    
        }

        questionIndex = Random.Range(0, questionPool.Length);
     

    }

Why do you set the index range after you already grab the random question? move the questionIndex = Random.Range(0, questionPool.Length); above your QuestionData questionData = questionPool[questionIndex];

2 Likes

After that, have you controlled the questionPoo.Lengh is greater than 0?

I know it was a simple typo, but it made me laugh and added some happiness to my day.

LOL, it was accidental

I can’t exactly grasp what you mean, I am basically frankensteining my way out this. I am new to this coding thing. But I really appreciate you guys helping me, thanks by the way. what do you mean by “controlling the questionPool.Length is greater than 0?”

If the questionPool.Lenght (not Poo, sorry) is equal to 0, the Random.Range is always equal to 0, and the question displayed is always the same, or you get the “Array is out of range” error

thanks man, and then what? What happens is when I randomly get to my last question, I tend to end the game, skipping all the other questions. I have a little knowledge on scripting as you can see. Appreciate the help man.

Nothing here ends the game. I think there must be another script involved — can you show us that one?

1 Like

Here is the whole code I used (again this is somewhat frankensteining my way out):

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

public class GameController : MonoBehaviour
{
    public SimpleObjectPool answerButtonObjectPool;
    public Text questionText;
    public Text scoreDisplay;
    public Text timeRemainingDisplay;
    public Transform answerButtonParent;

    public GameObject questionDisplay;
    public GameObject roundEndDisplay;
    public GameObject wrongOneDisplay;
    public GameObject wrongTwoDisplay;
    public GameObject wrongThreeDisplay;
    public GameObject wrongFourDisplay;
    public Text highScoreDisplay;
    public int lives = 4;

    private DataController dataController;
    private RoundData currentRoundData;
    private QuestionData[] questionPool;



    private bool isRoundActive = false;
    private float timeRemaining;
    private int playerScore;
    private int questionIndex;
    private List<GameObject> answerButtonGameObjects = new List<GameObject>();



    void Start()
    {
        dataController = FindObjectOfType<DataController>();                               

        currentRoundData = dataController.GetCurrentRoundData();                         
        questionPool = currentRoundData.questions;                                         

        timeRemaining = currentRoundData.timeLimitInSeconds;                               
        UpdateTimeRemainingDisplay();
        playerScore = 0;
      



        ShowQuestion();
        isRoundActive = true;

    }



    void Update()
    {
        if (isRoundActive)
        {
            timeRemaining -= Time.deltaTime;                                               
            UpdateTimeRemainingDisplay();

            if (timeRemaining <= 0f)                                                  
            {
                {
                    lives -= 1;

                    if (lives <= 0)
                    {
                        wrongFourDisplay.SetActive(true);
                        EndRound();
                    }

                    if (lives <= 2)
                    {
                        wrongTwoDisplay.SetActive(true);
                    }

                    if (lives <= 1)
                    {
                        wrongThreeDisplay.SetActive(true);
                    }

                    if (lives <= 3)
                    {
                        wrongOneDisplay.SetActive(true);
                    }
                }
               

                if (questionPool.Length > questionIndex +1)                                           
                {
                    questionIndex++;
                    ShowQuestion();
                    timeRemaining = currentRoundData.timeLimitInSeconds;                             
                    UpdateTimeRemainingDisplay();

                   
                }
                else
                {
                    EndRound();
                }

            }
        }

    }

    void ShowQuestion()
    {
        RemoveAnswerButtons();
        questionIndex = Random.Range(0, questionPool.Length);
        QuestionData questionData = questionPool[questionIndex];                          
        questionText.text = questionData.questionText;                                     
       

        for (int i = 0; i < questionData.answers.Length; i++)                              
        {
        

            GameObject answerButtonGameObject = answerButtonObjectPool.GetObject();        
            answerButtonGameObjects.Add(answerButtonGameObject);
            answerButtonGameObject.transform.SetParent(answerButtonParent);
            answerButtonGameObject.transform.localScale = Vector3.one;

            AnswerButton answerButton = answerButtonGameObject.GetComponent<AnswerButton>();
            answerButton.SetUp(questionData.answers[i]);                                   
        }

    }

    void RemoveAnswerButtons()
    {
        while (answerButtonGameObjects.Count > 0)                                          
        {
            answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
            answerButtonGameObjects.RemoveAt(0);
        }
    }




    public void AnswerButtonClicked(bool isCorrect)
    {
        if (isCorrect)
        {
            playerScore += currentRoundData.pointsAddedForCorrectAnswer;                   
            scoreDisplay.text = playerScore.ToString();

        }

        else                             
        {
            {
                lives -= 1;
            }
        }

        if (questionPool.Length > questionIndex + 1)                                           
        {
            questionIndex++;
            ShowQuestion();
            timeRemaining = currentRoundData.timeLimitInSeconds;                             
            UpdateTimeRemainingDisplay();
        }

        else

        {
            EndRound();
        }

        if (lives <= 0)
        {
            wrongFourDisplay.SetActive(true);
            EndRound();
        }

        if (lives <= 2)
        {
            wrongTwoDisplay.SetActive(true);
        }

        if (lives <= 1)
        {
            wrongThreeDisplay.SetActive(true);
        }

        if (lives <= 3)
        {
            wrongOneDisplay.SetActive(true);
        }
    }

    private void UpdateTimeRemainingDisplay()
    {
        timeRemainingDisplay.text = Mathf.Round(timeRemaining).ToString();
    }

    public void EndRound()
    {
        isRoundActive = false;
        dataController.SubmitNewPlayerScore(playerScore);
        highScoreDisplay.text = dataController.GetHighestPlayerScore().ToString();
       
        questionDisplay.SetActive(false);
        roundEndDisplay.SetActive(true);
    }

How is the game supposed to run? You say you get to your last question and then you can’t get the rest to display… If it’s the last question then that’s game over right?

OK, it looks to me like the problem is the ‘else’ clause on lines 172-176. That (with the if-statement on line 164) basically says, if we just showed the last question, end the round. You were probably thinking “if we have no more questions” but since you’re picking questions in random order, it really means “if we happen to have just shown the last question on our list (regardless of whether there are others we haven’t shown)”.

But actually, this gets to the deeper problem implied by your thread title, but not actually addressed here… you want to show these questions in a shuffled order, not just randomly pick a (possibly already-seen) question each time.

So it’s time to back up and rethink a little. The best way to do this is:

  • In Start, around line 50, shuffle your questions. Sadly C# does not have a built-in way to do this, so create a new script, delete the default stuff Unity gives you, and paste in the code from this answer. Then you should be able to just say new Random().Shuffle(questionPool) to get the job done.
  • In your ShowQuestion method, take out the Random.Range business. Instead simply increment questionIndex by 1.
  • You’ll probably then find that it’s skipping the first question. To fix that, in Start, simply set questionIndex = -1 before calling ShowQuestion.

The rest of your code should be OK; it will show the questions in random order, and exit after the last question (which is now the right thing to do), or when the player is out of lives.

Yeah, I want all my questions to be displayed only not in the same order. But because of the random script, sometimes the last question appears second or fifth, etc. and if appears early, the game ends too.

Thank you very much, I really appreciated your help.

Yeah, since you run out of questions, what you want to do is not to just move to the next question in line. Where you do questionIndex ++. Or you can do that but once questionIndex = questionPool.Length-1 then set it to 0 and start adding to it

It works fantastic!! It shuffles the order and repetition of questions are gone. I am really thankful to you man! By the way, if it is not a burden to you, do you have any idea on where should I put the EndRound()?
As the the game doesn’t really end if you answered all the questions correctly, or if you still have lives. It just give an error of IndexOutOfRangeException. What happens is, you have to wait for the last question’s time to end in order for it to move to the round end display. But again, really thankful to you as you solved my 2 day old problem. Kudos to you my friend!

Hmm, I’m not sure about that one. On what line does this error happen?

during game play

it doesn’t end or bring you to the round end display if you answered all the questions, but if you wait for the given time to end, it moves to the round end display. Can I make it move to the round end display as soon as the questions are all answered? by the way, thanks for the help again man.

OK, when you get an exception, double-click the error message in the Console window. That should open the source file and take you right to the line where it occurred.

(If for some reason that doesn’t work, if you read the error message carefully, it also tells you where it occurred, as well as how it got there!)