7
\$\begingroup\$

I have a coroutine that smoothly changes a variable in my UI, but when I pause the game, the coroutine pauses too. How can I fix that?

Code:

using UnityEngine;
using System.Collections;

public class HUDController : MonoBehaviour {
    public void PauseGame() {
        FreezeTime();
        StartCoroutine(ShowPauseMenu());
    }

    private void FreezeTime() {
        Time.timeScale = 0;
    }

    private IEnumerator ShowPauseMenu() {
        var pauseMenuCanvasGroup = GameObject.FindWithTag("PauseMenu").GetComponent<CanvasGroup>();
        var alphaValue = 1f;
        var velocity = 0f;
        var time = 0.15f;

        while (!Mathf.Approximately(pauseMenuCanvasGroup.alpha, alphaValue)) {
            pauseMenuCanvasGroup.alpha = Mathf.SmoothDamp(pauseMenuCanvasGroup.alpha, alphaValue, ref velocity, time);
            yield return null;
        }

        pauseMenuCanvasGroup.alpha = 1; // Since float is not accurate, manually set the alpha to 1
        pauseMenuCanvasGroup.interactable = true;
    }
}
\$\endgroup\$
6
  • \$\begingroup\$ I'm unable to reproduce this issue in Unity 5. In my tests, coroutines that yield return null or new WaitForEndOfFrame() keep humming along just fine when Time.timeScale = 0 - it's only yield return new WaitForSeconds(delay) that pause. Can you confirm what version of Unity you're running? \$\endgroup\$
    – DMGregory
    Commented Jan 10, 2016 at 14:00
  • \$\begingroup\$ @DMGregory 5.2.3f1 \$\endgroup\$ Commented Jan 10, 2016 at 14:01
  • \$\begingroup\$ How sure are you that the timescale is the cause? Have you tried to not set the timescale to zero and still run the coroutine? \$\endgroup\$
    – Athos vk
    Commented Jan 10, 2016 at 14:09
  • \$\begingroup\$ Yes, I removed the timescale and it runs just fine \$\endgroup\$ Commented Jan 10, 2016 at 14:42
  • \$\begingroup\$ Can anyone help? \$\endgroup\$ Commented Jan 10, 2016 at 18:59

2 Answers 2

13
\$\begingroup\$

This is sure to happened because Mathf.SmoothDamp uses Time.deltaTime in default calculation. When you set Time.timeScale = 0 then Mathf.SmoothDamp won't give the expected value but only first value, repeatedly.

You can further verify by printing alpha value to console, print it in your while loop so that you can confirm it by the unlimited logs of same value.

Here is the Documentation on Mathf.SmoothDamp.

You can fix this by passing your own deltaTime to keep it from using its default Time.deltaTime. Just add one more parameter to the end of the call:

pauseMenuCanvasGroup.alpha = Mathf.SmoothDamp(
  pauseMenuCanvasGroup.alpha, 
  alphaValue, 
  ref velocity, 
  time,
  1000,          // <-- Fifth parameter Optionally allows you to clamp the maximum speed.
  1.0f/30.0f);   // <-- Add a sixth parameter representing your framerate.

You can use a function that measures realtime elapsed instead of a constant, if your rendering framerate is variable.

\$\endgroup\$
4
  • 3
    \$\begingroup\$ Dontcha love it when methods do something totally unexpected for completely reasonable (if hard to discern) reasons? \$\endgroup\$ Commented Jan 11, 2016 at 19:15
  • \$\begingroup\$ It doesn't work. It still gives only the first value. \$\endgroup\$ Commented Feb 18, 2016 at 20:59
  • \$\begingroup\$ @Milen yup, that was a little mistyping there, actually that should be the 6th parameter instead of 5th, 5th is the max speed. Check the edits \$\endgroup\$ Commented Feb 18, 2016 at 21:38
  • \$\begingroup\$ @Milen now the code is tested thoroughly :) Give it a try :) \$\endgroup\$ Commented Feb 18, 2016 at 22:08
0
\$\begingroup\$

I had this problem and the situation was like this, and I SOLVED IT. User presses the pause button then some objects goes off (these objects has couroutine(s) ). THIS IS THE PROBLEM. I must not turn off those game objects. The coroutines working fine while the game object is on and when you turn them off every thing is going to be mess.

\$\endgroup\$

You must log in to answer this question.

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