Wait for seconds HELP !

I have this script and i want in the point that user select true and the question is false that means that in the script goes to else point to wait a number of seconds for example 3 and then to activate the panel. If it is possible i want it to be happent without creating an coroutine and use enumerators. Thanks in advanced.

    public void UserSelectTrue ()
    {
        animator.SetTrigger("True");
        if (currentQuestion.isTrue)
        {
            SceneManager.LoadScene (SceneManager.GetActiveScene ().buildIndex);
        }
        else
        {
            panel.SetActive (true);
        }

        StartCoroutine (TransitionToNextQuestion ());
    }

This is the whole script.

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

public class GameManager : MonoBehaviour {

    [SerializeField]
    private GameObject panel;

    [SerializeField]
    private string menu;

    public Question[] questions;
    private static List<Question> unansweredQuestions;

    private Question currentQuestion;

    [SerializeField]
    private Text factText;

    [SerializeField]
    private float timeBetweenQuestions = 1f;

    [SerializeField]
    private Text trueAnswerText;

    [SerializeField]
    private Text falseAnswerText;

    [SerializeField]
    private Animator animator;

    void Start ()
    {

        if (unansweredQuestions == null || unansweredQuestions.Count == 0)
        {
            unansweredQuestions = questions.ToList<Question> ();
        }

        SetCurrentQuestion();
    }

    void SetCurrentQuestion ()
    {
        int randomQuestionIndex = Random.Range (0, unansweredQuestions.Count);
        currentQuestion    = unansweredQuestions [randomQuestionIndex];

        factText.text = currentQuestion.fact;

        if (currentQuestion.isTrue) {
            trueAnswerText.text = "CORRECT";
            falseAnswerText.text = "WRONG";
        }
        else
        {
            trueAnswerText.text = "WRONG";
            falseAnswerText.text = "CORRECT";
        }
       
    }

    IEnumerator TransitionToNextQuestion ()
    {
        unansweredQuestions.Remove (currentQuestion);

        yield return new WaitForSeconds (timeBetweenQuestions);
    }
    public void UserSelectTrue () // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    {
        animator.SetTrigger("True");
        if (currentQuestion.isTrue)
        {
            SceneManager.LoadScene (SceneManager.GetActiveScene ().buildIndex);
        }
        else
        {
            panel.SetActive (true);
        }

        StartCoroutine (TransitionToNextQuestion ());
    }
        public void UserSelectFalse()
    {
        animator.SetTrigger("False");
        if (!currentQuestion.isTrue)
        {
            SceneManager.LoadScene (SceneManager.GetActiveScene ().buildIndex);
        }
        else
        {
            panel.SetActive (true);
        }

        StartCoroutine (TransitionToNextQuestion ());
    }
}

There is only 2 ways to wait 3 seconds before doing something. Using a Coroutine with yield WaitForNewSeconds, or having your Update() function keep track of when your 3 seconds starts, have a variable keep adding time from Time.deltaTime and then trigger when that variable goes over 3 seconds.

Since you not using Update at all in this code, I think Coroutine is exactly what you need.

When you say:

Is the panel your referring to this panel (the one you activate before calling the CoRoutine:

else
        {
            panel.SetActive (true);
        }
        StartCoroutine (TransitionToNextQuestion ());

If so just move that line into the Coroutine

 IEnumerator TransitionToNextQuestion ()
    {
        unansweredQuestions.Remove (currentQuestion);
        yield return new WaitForSeconds (timeBetweenQuestions);
        panel.SetActive(true);
    }

Also at some point you’ll need to call SetCurrentQuestion. What does the LoadScene do, and what does the panel show when you setactive. Both of the cases right or wrong, at some point have to load up the next question with SetCurrentQuestion

i want the panel to be activated when the anwser that you chose is wrong for exaple if the question is true and you anwse wrong then wait 3 seconds because i have an animation that i want be be played and then to activate the panel.Inside the UserSelectTrue function that i have put into a button.

In that case just move the panel.SetActive(true) inside the Coroutine like i showed. And move the StartCoroutine into the else.

I assume the LoadScene is starting a new question batch or something? If thats true then the Coroutine will also need a SetupNextQuestion in it as well, since your not loading a scene when they get it wrong. Maybe after another Yield WaitforSEconds

I think that i done what you said but when i put yield return WaitForSeconds (2); in the if this message appeard on the editor: The body of GameManager.UserSelectFalse()’ cannot be iterator block because ‘void’ is not an iterator interface type. Can you please post the piece of my code with that you said in a case that i do it wrong again

using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
    [SerializeField]
    private GameObject panel;
    [SerializeField]
    private string menu;
    public Question[] questions;
    private static List<Question> unansweredQuestions;
    private Question currentQuestion;
    [SerializeField]
    private Text factText;
    [SerializeField]
    private float timeBetweenQuestions = 1f;
    [SerializeField]
    private Text trueAnswerText;
    [SerializeField]
    private Text falseAnswerText;
    [SerializeField]
    private Animator animator;
    void Start ()
    {
        if (unansweredQuestions == null || unansweredQuestions.Count == 0)
        {
            unansweredQuestions = questions.ToList<Question> ();
        }
        SetCurrentQuestion();
    }
    void SetCurrentQuestion ()
    {
        int randomQuestionIndex = Random.Range (0, unansweredQuestions.Count);
        currentQuestion    = unansweredQuestions [randomQuestionIndex];
        factText.text = currentQuestion.fact;
        if (currentQuestion.isTrue) {
            trueAnswerText.text = "CORRECT";
            falseAnswerText.text = "WRONG";
        }
        else
        {
            trueAnswerText.text = "WRONG";
            falseAnswerText.text = "CORRECT";
        }
      
    }
    IEnumerator TransitionToNextQuestion ()
    {
        unansweredQuestions.Remove (currentQuestion);
        yield return new WaitForSeconds (timeBetweenQuestions);
        panel.SetActive (true);
    }
    public void UserSelectTrue () // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    {
        animator.SetTrigger("True");
        if (currentQuestion.isTrue)
        {
            SceneManager.LoadScene (SceneManager.GetActiveScene ().buildIndex);
        }
        else
        {
            StartCoroutine (TransitionToNextQuestion ());

        }
       
    }
        public void UserSelectFalse()
    {
        animator.SetTrigger("False");
        if (!currentQuestion.isTrue)
        {
            SceneManager.LoadScene (SceneManager.GetActiveScene ().buildIndex);
        }
        else
        {
            StartCoroutine (TransitionToNextQuestion ());
         
        }
       
    }
}

This way when they get the answer wrong it starts the coroutine which waits for 3 seconds then loads your panel

Invoke()?

1 Like

Oops forgot about that one.

Invoke is good to use in a lot of cases, especially if you are not comfortable with Coroutines since they can be less efficient and clutter the code if wrongly used. Only problem with Invoke is the string parameter but it can be made a constant to avoid bugs.

1 Like

You can also use MEC. MEC has a function called Timing.CallDelayed that does exactly what you want (also CallContinously and CallPeriodically).