Freeze game using Time.timeScale = 0, wait 3 secs and resume play automatically. Is it possible?

I'd like to use time.timescale = 0 to freeze the game, show an image, wait 3 seconds based on a timer, and then resume automatically using time.timescale = 1; I think 'yield return new WaitForSeconds(3F);' doesn't work when time.timescale == 0. Am I wrong? :)

Is there some other way, if I'm right with the above?

Thanks!

You're right, if you set the timescale to zero, the WaitForSeconds command won't work. For example, in the following code, the "WaitForSeconds" actually ends up taking 10 times as long as whatever duration is provided (as the variable 'p') to complete because of the timescale:

private IEnumerator Pause(int p)
{
    Time.timeScale = 0.1f;
    yield return new WaitForSeconds(p);
    Time.timeScale = 1;
}

And with a timescale of 0.0, the WaitForSeconds never completes. The way around this is to time the duration yourself using the Time.realtimeSinceStartup property, which works independently of the timeScale. See the following example:

private IEnumerator Pause(int p)
{
    Time.timeScale = 0.1f;
    float pauseEndTime = Time.realtimeSinceStartup + 1;
    while (Time.realtimeSinceStartup < pauseEndTime)
    {
        yield return 0;
    }
    Time.timeScale = 1;
}

A simpler but effective way is just to use a really small value for timeScale. Unless you intend on waiting literally for thousands of years, it's just as good as 0.

function PauseWaitResume (pauseDelay : float) {
    Time.timeScale = .0000001;
    yield WaitForSeconds(pauseDelay * Time.timeScale);
    Time.timeScale = 1.0;
}

In my opinion the simplest way to do this is by using WaitForEndOfFrame() function in Coroutine and Time.unscaledDeltaTime for timer.

void PauseAndResume()
{
         Time.timeScale = 0;

         //Display Image here

         StartCoroutine(ResumeAfterNSeconds(3.0f));
}

float timer = 0;
IEnumerator ResumeAfterNSeconds(float timePeriod)
{
         yield return new WaitForEndOfFrame();
         timer += Time.unscaledDeltaTime;
         if(timer < timePeriod)
                    StartCoroutine(ResumeAfterNSeconds(3.0f));
         else
         {
                    Time.timeScale = 1;                //Resume
                    timer = 0;
         }
}

I hope it helps, Cheers.

This function probably didn’t exist at the time of the OP, but there is a WaitForSecondsRealTime now.

The answers accepted at the time of writing this reply are from 2010. The Unity API has changed a lot since then, and now Time.unscaledDeltaTime is also available, which makes doing this a lot easier:

private IEnumerator PauseForSeconds (float pauseDuration) {
    float originalTimeScale = Time.timeScale; // store original time scale in case it was not 1
    Time.timeScale = 0; // pause
    float t = 0;
    while (t < pauseDuration) {
        yield return null; // don't use WaitForSeconds() if Time.timeScale is 0!
        t += Time.unscaledDeltaTime; // returns deltaTime without being multiplied by Time.timeScale
    }
    Time.timeScale = originalTimeScale; // restore time scale from before pause
}

A very simple method I found out today for a 3 second timer:

IEnumerator countdownTimer()
    {
        yield return new WaitForSecondsRealtime(1);
        countdown.text = "2";
        yield return new WaitForSecondsRealtime(1);
        countdown.text = "1";
        yield return new WaitForSecondsRealtime(1);
        Time.timeScale = 1;
        countdown.gameObject.SetActive(false);
        countdown.text = "3";
    }

countdown is a text object, and once the player presses pause do countdown.gameobject.SetActive(true);

Try this out, 100% Working
The reason is “WaitForSecondsRealtime” is execute independent of Time.timeScale

IEnumerator nowResume()
    {
       
        for (int i =3; i>=0; i--)
        {
           
            resumeCountDownobj.GetComponent<Text>().text = i.ToString();
           
            yield return new WaitForSecondsRealtime(1);
            

        }

        
        resumeCountDownobj.SetActive(false);
       Time.timeScale = 0;
}

Try using an IEnumerator, for example =

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace Game
{

class Script : MonoBehaviour
{
private float originalTimeScale;

void Start()
{
originalTimeScale = Time.timeScale;

StartCoroutine(FreezeAndUnfreeze(3f))
}

IEnumerator FreezeAndUnfreeze(float timeToWait)
{
Time.timeScale = 0f;

yield return new WaitForSeconds(timeToWait)

Time.timeScale = originalTimeScale;
}
}
}

Can use WaitForSecondsRealtime() as well
in the doc: Unity - Scripting API: WaitForSecondsRealtime
can be used similar to WaitForSeconds()

IEnumerator HitPause(float duration)
{
Time.timeScale = 0f;
yield return new WaitForSecondsRealtime(duration);
Time.timeScale = 1.0f;
}

WaitForSecondsRealtime USE THIS instead of WaitForSeconds

You can do it in such a way.
IEnumerator ResumeAfterAction(){
Time.timeScale = 0f;
yield return new WaitForSecondsRealtime ();
Time.timeScale = 1f;

}