Reputation: 51
I need to play like a pop-out animation (growing smaller) and after that move the UI-Elements from the animation out of the canvas.
I've tried various things, like
bool AnimatorIsPlaying(){
return animator.GetCurrentAnimatorStateInfo(0).length >
animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
}
or
bool AnimatorIsPlaying(){
return animator.GetCurrentAnimatorStateInfo(0).normalizedTime < 1;
}
and more, almost all from this https://answers.unity.com/questions/362629/how-can-i-check-if-an-animation-is-being-played-or.html question.
Sometimes, the things, if in an if clause with the bools, didn't move out at all, or they moved out too soon, like if nothing even was added. I've even tried making the method a IEnumerator so that I could do a yield return new WaitForSecondsRealtime(0.25f) but then I couldn't call the method from an other class anymore(which IS neccessary).
Now I've found an Method which is just calling an method from the other class and then starting a Coroutine with yield return new WaitForSecondsRealtime(0.25f). But is there a better method and why da frick was it not working?
Upvotes: 2
Views: 2856
Reputation: 28
Kinda faced a similar problem a few weeks ago... this is how I fixed it:
I set my AnimationController that it starts the next Animation immediately after completing the current one. (In case you don't have an Animation afterwards just use an empty one as an Idle State) Then in my Code after starting my Animation I use a coroutine to wait until the "Idle-Animation" has started (and therefore your original Animation has ended) It worked perfectly for me so maybe it will work for you too!
Here is the code for the coroutine:
public IEnumerator WaitForAnimationFinished()
{
yield return new WaitUntil( delegate { return playerAnimator.GetCurrentAnimatorStateInfo(0).IsName("YourIdleAnimationName"); });
// Move the UI-Elements from the animation out of the canvas
}
I guess it is not the best solution but to make it able to be called from another class you could add a public static MyScriptInstance
variable in the Script where you save the Method above. Then you could just call your Method with
StartCoroutine(MyScript.MyScriptInstance.WaitForAnimationFinished())
I hope I was able to help you with that! :)
Upvotes: 3
Reputation: 3
If you use an animator, you can use this :
In your animation windows, you have a button called "Add Event" (look the First picture)
He will create a little mark on on timeline, you can move it wherever you want. And if you click on it, in the inspector, you will have several options (look the Second Step)
You need to put the name of the function. For the float, int or the string, it's just parameter if you have one in your function. And the last parameters is the object with the script who contains the function you want to call (you need to put the function in public if you to use it).
I hope this will help you !
Upvotes: 0
Reputation: 772
Method 1 Invoke() method, set a variable (this variable will be used next):
private float duration;
Invoke("method name", wait time); Add this to your method body: Invoke("MethodName", duration); Don't forget to add the method named MethodName:
private void MethodName()
{
//Write here the content to be executed after duration seconds
}
What is written in the MethodName method is the content to be executed after duration seconds.Invoke(nameof(method name), wait time);
Invoke(nameof(MethodName), duration);
private void MethodName()
{
//Write here the content to be executed after duration seconds
}
Because the parameters in nameof() can point directly to your method. Using the method name in string form is always worried that it will be misspelled. If there are too many lines of code, it is also more troublesome to find the MethodName method.
Method 2 Coroutine: Affected by time scaling, if you want the waiting time to be affected by time scaling, that is, update time, then you can write a coroutine method like this:
Waiting time (affected by Time.timeScale)
<param name="duration">Wait time</param>
<param name="action">The function to be executed after
waiting</param>
<returns></returns>
public static IEnumerator WaitForSeconds(float duration, Action action = null)
{
yield return new WaitForSeconds(duration);
action?.Invoke();
}
Then add this to your method body:
StartCoroutine(WaitForSeconds(duration, () =>
{
//Write here the content to be executed after duration seconds
}))
Not affected by time scaling, if you want the waiting time to be unaffected by time scaling, that is, real time, then you can write a coroutine method like this:
<summary>
Waiting time (not affected by Time.timeScale)
</summary>
<param name="duration">Wait time</param>
<param name="action">The function to be executed after waiting</param>
<returns></returns>
public static IEnumerator WaitForSecondsRealtime(float duration, Action action = null)
{
yield return new WaitForSecondsRealtime(duration);
action?.Invoke();
}
Then add this to your method body:
StartCoroutine(WaitForSecondsRealtime(duration, () =>
{
//Write here the content to be executed after duration seconds
}))
Hope it helps you.
Upvotes: 0
Reputation: 233
This problem can be worked around in several ways. From a timer counting up/down (with the animation speed variable to count against), to a coroutine (one of my preferences) as Pretzl mentioned.
You can also use Animations Events. Simply create a function with your code to be called, add an event at the end of your animation, and it will be called at that point.
See more about animation events here.
Upvotes: 1