Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Pause Script until Animation is finished.

Discussion in 'Scripting' started by twobit0, Jul 17, 2018.

  1. twobit0

    twobit0

    Joined:
    Jun 17, 2018
    Posts:
    13
    there are alot of examples of the old animation.isplaying but not alot for the new system. this code just seems to end instantly before its done playing. I want the script to wait until the animation has finished playing.

    IEnumerator playAnim()
    {

    int animLayer = 0;

    anim.SetTrigger(Animationcall);

    //Wait until Animator is done playing
    while (anim.GetCurrentAnimatorStateInfo(animLayer).IsName(Animationcall) &&
    anim.GetCurrentAnimatorStateInfo(animLayer).normalizedTime < 1.0f)
    {
    //Wait every frame until animation has finished
    yield return null;
    }

    //Done playing. Do something below!
    Debug.Log("Done Playing");

    }
     
  2. mjzx

    mjzx

    Joined:
    Aug 18, 2013
    Posts:
    114
    Okay, you should read this thread before you start posting:
    https://forum.unity.com/threads/using-code-tags-properly.143875/

    What do you mean you want "the script" to wait until the animation finishes playing? Do you want specific lines of code to only work, or everything?

    The code you posted should be a fine starting point. You could simply declare a boolean variable called something like
    isFinishedAnim
    and set it to false. Then at the end of the coroutine you posted, set
    isFinishedAnim
    to true. To "pause" all of your script, just put an if statement:
    Code (CSharp):
    1. if (isFinishedAnim)
    before all your code you want to pause.

    Let me know if that wasn't clear enough ;)
     
  3. twobit0

    twobit0

    Joined:
    Jun 17, 2018
    Posts:
    13
    Sorry about the code pasting.

    Code (CSharp):
    1.  IEnumerator playAnim()
    2.     {
    3.  
    4.         isFinishedAnim = false;
    5.         int animLayer = 0;
    6.  
    7.         anim.SetTrigger(Animationcall);
    8.  
    9.         //Wait until Animator is done playing
    10.         while (anim.GetCurrentAnimatorStateInfo(animLayer).IsName(Animationcall) &&
    11.         anim.GetCurrentAnimatorStateInfo(animLayer).normalizedTime < 1.0f)
    12.         {
    13.             //Wait every frame until animation has finished
    14.             yield return null;
    15.         }
    16.         //Done playing. Do something below!
    17.         Debug.Log("Done Playing");
    18.         isFinishedAnim = true;
    19.        
    20.     }
    I added a if (isFinishedAnim) {} after the coroutine but it still runs the rest of the script before the animation is finished. might be a problem with my while code? This type of function seemed easier in previous versions of unity.
    I would like to pause the entire script, or just a few lines.. either way.. doesnt seem to be working.
     
  4. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,117
    Depending on whether this is a specific animation you're playing, another approach is to use Animation Events. Basically, within the animation clip itself you can call methods as specific times. You might consider placing an animation event within your animation, towards the end of the animation, and have it call a method that resumes your script when it's called.
     
  5. twobit0

    twobit0

    Joined:
    Jun 17, 2018
    Posts:
    13
    thats not a bad idea, but I have so many animations that it would be alot less work for me just to run a few lines after its done. hmmm
     
  6. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,117
    That's probably true.

    To your original question, you probably just need to step through the code and see what the values are. A couple of things that might be an issue, worth checking on:
    • After your trigger, does the clip change immediately? Often animators have a transition period between two states, so your animation might not be in the state you expect immediately upon firing a trigger.
    • Have you confirmed you don't have a typo in the trigger name, such that you're not transitioning at all?
    In any case, try putting a breakpoint, or a Debug statement, above and within your While loop, to inspect what the actually values are, to understand why you're not remaining in your loop longer.
     
  7. twobit0

    twobit0

    Joined:
    Jun 17, 2018
    Posts:
    13
  8. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,117
    You need to look into the values in your code to understand why they aren't what you expect. For example, here's the code you posted earlier:

    Code (CSharp):
    1. while (anim.GetCurrentAnimatorStateInfo(animLayer).IsName(Animationcall) &&
    2.         anim.GetCurrentAnimatorStateInfo(animLayer).normalizedTime < 1.0f)
    So, in order to enter (and remain) in that `while` loop, two things need to be true. Are they true? Put a breakpoint on this line of code, and add entries to the Watch window for each. It will tell you which of the two is false.

    One potentially obvious issue is that you're calling SetTrigger to `Animationcall`, and you're calling IsName on `Animationcall`. SetTrigger needs to pass in the name of a parameter, while IsName expects the name of an animation state. Those aren't necessarily the same thing, though it's possible you named your trigger exactly the same thing as your animation state.

    Anyway, I think what you really need is to familiarize yourself with the debugging tools. You should be able to run the game and verify that your trigger has changed the animator's state as expected. And you should be able to attach the debugger and verify the values of different variables in your code. If you don't learn to do those kinds of things, you'll just be guessing at what's wrong, and that's often very hard to do.
     
  9. mjzx

    mjzx

    Joined:
    Aug 18, 2013
    Posts:
    114
    Sorry, what I mean't was, put the
    if (isFinishedAnim) {}
    around the parts of your code that you want to pause, not in the coroutine. For example:
    Code (CSharp):
    1.  
    2. private IEnumerator PlayAnim () {
    3.     isPlayingAnim = true;
    4.  
    5.     // Play animation here....
    6.     yield return new WaitForSeconds(1.0f);
    7.  
    8.     isPlayingAnim = false;
    9. }
    10.  
    11. // Called every frame
    12. void Update () {
    13.     if (isFinishedAnim) {
    14.         // This code will only run when the animation finishes.
    15.     }
    16. }
    ^^^ (Assuming PlayAnim coroutine is called/started from some other function.)
     
    Last edited: Jul 19, 2018
  10. twobit0

    twobit0

    Joined:
    Jun 17, 2018
    Posts:
    13
    for some reason the "yield return new WaitForSeconds(1.0f);" just the statement alone in its own test scene does nothing. even if i set it for 4000, 4000f it just finished immediately.
     
  11. Issun

    Issun

    Joined:
    Nov 7, 2013
    Posts:
    17
    I'm not familiar at all with the animation system but this coroutine is probably worth a shot i think..

    Code (CSharp):
    1. IENumerator Routine()
    2. {
    3.    // play the animation
    4.  
    5.    while(!animationDone)
    6.         yield return new WaitForEndOfFrame();
    7.  
    8.    // stuff to do when the animation finishes.
    9.  
    10. }
    This will get stuck in the while loop while the animation is playing.
    Each frame it will check again if the animation is finished yet, if it is the while loop will terminate, then you put your code you want to run once the animation is finished.

    (Replace "animationDone" with whatever the code is to check that kind of thing)