1
\$\begingroup\$

I have an array of gameobjects (some questions) if player hit some triggers a question from the array is displayed randomly, I want to avoid duplication of displaying questions.

 public GameObject[] Q;
 public static int ColliderCounter = 0;
 int WrongAnswerCounter = 0;
 public int i,old;

 private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "Obstcle")
        {
            i = Random.Range(0, Q.Length);
            old = i;
            ColliderCounter++;
            Q[i].SetActive(true);
            GetComponent<PlayerMovement>().enabled = false;
        }

    }

 IEnumerator waitWrongAnswer()
    {
            WrongAnswerCounter++;

            yield return new WaitForSeconds(3f);
            Q[old].SetActive(false);
            i++;
            Q[i].SetActive(true);
            old = i;
    }

And I want to know how to check if all questions are displayed do something.

Thanks in advance

\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

Common approach

  1. Shuffle your array. A simple Fisher–Yates shuffle will do. The result is that you will have your array of GameObject in a random order.

  2. When picking a GameObject to activate, just pick the next one. To do that, you keep an int index field that tells you where you are so far, it starts at zero... then, on the event, you pick the GameOBject at that index, and increment the index.

    The result is that they are activated in a random order (because, remember, you did shuffle them) and there is no chance of duplicates.

  3. It also very easy to tell when you activated all of the objects (index == Q.Length).

To give you an intuition of this method, think of your questions as a deck of cards, you start by shuffling it, and then you deal the cards knowing they are already shuffled. You know that you have dealed all the cards when you reach the end of the deck. There are no duplicates because each card is only once in the deck.

I would advice to implement the Fisher–Yates algorithm yourself, it is only four lines of C#, so do not be intimidated by it.

Alternative approach

Let us say that you do not want the order to be selected before hand (even if the user does not know the order). In that case, this is what you do:

  1. Have a field List<int> L and initialize it with the numbers from 0 to Q.Length - 1 inclusive (this is a simple for loop, or a linq query if you want to be fancy - don't be fancy).

  2. When picking GameObject to activate, select an int index at random from 0 to L.Count - 1 inclusive (you do something similar to this in your code) and activate Q[L[index]] (that is the element of Q which index is the element of L which index is index). Afterwards, remove it from the list (L.RemoveAt(index)).

    As you can see, you are selecting the items at random from a list that contains all items yet to be selected. By removing the one selected each time, you make sure that there are no duplicates.

  3. It is very easy to tell when you are done (L.Count == 0).

To give you an intuition of this method, imagine each question is a person, and each person has a number, then you make papers with the numbers of each person and throw them into a bag, and take them one by one - at random - you know that you have taken all when the bag is empty. There are no duplicates because you do not add the same number in the bag twice.

Have a read about Random.Range, notice that it returns a float, also notice that both min and max are inclusive (they are possible results).


Notes

The alternative method is more memory intensive than the common one because it requires to create a new list.

The only advantage that the alternative method has is that it makes it easier to implement a save and load feature such that the questions that are yet to be revealed appear in a different order on every load. This is still possible with the common approach, however it requires a careful re-shuffle (re-shuffle only the questions yet to be revealed).

Notice also that logic of both methods is similar in abstract terms. The main difference is that common approach is eager to randomize, while the alternative is lazy.

\$\endgroup\$
1
  • \$\begingroup\$ @Sh.Adel I expanded my answer, I believe I have explained enough for you to at least try it. I cannot write it for you, there are details of your code I do not know. Tell me if there is something that is not making sense to you. \$\endgroup\$
    – Theraot
    Commented Nov 13, 2018 at 10:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .