3
votes

I am working on a simple animation for my UI elements.

I have an animator component which has 2 different animations - ZoomIn and ZoomOut.

These animations are displayed whenever an UI element (e.g. Button) needs to be displayed on the screen.

I normally prefer deactivating the gameobject when not displaying.

I have written the following method for the animations:

private IEnumerator ToggleObjectWithAnimation (GameObject gameObj) {
        Animator gameObjectAnimator = gameObj.GetComponent ();   // Animator is set to unscaled time
        if (gameObj.activeSelf == false) {
            gameObj.transform.localScale = new Vector3 (0, 0, 1.0f);
            gameObj.SetActive (true);
            gameObjectAnimator.SetTrigger ("ZoomIn");
            yield return new WaitForSeconds (0.5f);
        } else if(gameObj.activeSelf == true) {
            gameObjectAnimator.SetTrigger ("ZoomOut");
            yield return new WaitForSeconds (0.5f);
            gameObj.SetActive (false);   // code not execute when timescale = 0
        }
        yield return null;
}

The code works fine when for most of the screens, but shows problem when I pause the game using timescale = 0.

When timescale is 0, the line gameObj.SetActive (false) does not work.

1
how about you put Debug.Log("test"); before gameObj.SetActive (false); and see if if the Log shows up.Programmer
It's a good example of why you never change the timeScale in Unity. Pausing a game is very difficult and involves a lot of code. You have to write pause routines for every element in the game. A few years ago someone on the internet mentioned that you can "change the timeScale" to pause a game in Unity, which is just ridiculous. That comment has been repeated all over the internet and now beginners and hobbyists have their time wasted with it.Fattie
I have already tried adding Debug.Logs.Probal Kumar Das
The code is breaking in the else block after the line - yield return new WaitForSeconds (0.5f); Though the Log after the yield statement is not displayed but I am sure that the yield block is executed as I am able to see the animation. But the line - gameObj.SetActive (false) is never executed.Probal Kumar Das
@Joe Blow - Thanks for the suggestion. I didn't knew that changing the timescale is a bad practice. Although I have tried pausing my game without using timescale, but I have a major challenge in doing so. My game is paused when my character hits an unexpected object. Now, my character can be in the process of executing a certain animation when it collides with the other object. So while pausing my game I want my character to be in the interim state of animation, rather completing it. This was easy to achieve using timescale = 0.Probal Kumar Das

1 Answers

6
votes

I know it's probably a bit late but:

The problem is not the SetActive but that WaitForSeconds si affected by the Time.timeScale!

The actual time suspended is equal to the given time multiplied by Time.timeScale. See WaitForSecondsRealtime if you wish to wait using unscaled time.

So if you have Time.timescale=0 the WaitForSeconds will never finish!


You shoul rather use WaitForSecondsRealtime

private IEnumerator ToggleObjectWithAnimation (GameObject gameObj) 
{
    Animator gameObjectAnimator = gameObj.GetComponent ();   // Animator is set to unscaled time

    if (gameObj.activeSelf == false) 
    {
        gameObj.transform.localScale = new Vector3 (0, 0, 1.0f);
        gameObj.SetActive (true);
        gameObjectAnimator.SetTrigger ("ZoomIn");
        yield return new WaitForSecondsRealtime(0.5f);
    } 
    else if(gameObj.activeSelf == true) 
    {
        gameObjectAnimator.SetTrigger ("ZoomOut");
        yield return new WaitForSecondsRealtime(0.5f);
        gameObj.SetActive (false);   // code not execute when timescale = 0
    }
    yieldr eturn null;
}