Play and wait for Animation/Animator to finish playing
While both answers should work, another method of doing this with coroutine and the IsPlaying
function. You use the coroutine solution if you also want to perform other task after the animation.
For the Animation
system:
The old Unity animation playback system. This should not be used in your new Project unless you are still using old Unity version.
IEnumerator playAndWaitForAnim(GameObject target, string clipName)
{
Animation anim = target.GetComponent<Animation>();
anim.Play(clipName);
//Wait until Animation is done Playing
while (anim.IsPlaying(clipName))
{
yield return null;
}
//Done playing. Do something below!
Debug.Log("Done Playing");
}
For the Animator
system
This is the new Unity animation playback system. This should be used in your new Project instead of the Animation
API. In terms of performance, it's better to use the Animator.StringToHash
and compare the current state by hash number instead of the IsName
function which compares string since the hash is faster.
Let's say that you have state names called Jump
, Move
and Look
. You get their hashes as below then use the function for playing and waiting for them them below:
const string animBaseLayer = "Base Layer";
int jumpAnimHash = Animator.StringToHash(animBaseLayer + ".Jump");
int moveAnimHash = Animator.StringToHash(animBaseLayer + ".Move");
int lookAnimHash = Animator.StringToHash(animBaseLayer + ".Look");
public IEnumerator PlayAndWaitForAnim(Animator targetAnim, string stateName)
{
//Get hash of animation
int animHash = 0;
if (stateName == "Jump")
animHash = jumpAnimHash;
else if (stateName == "Move")
animHash = moveAnimHash;
else if (stateName == "Look")
animHash = lookAnimHash;
//targetAnim.Play(stateName);
targetAnim.CrossFadeInFixedTime(stateName, 0.6f);
//Wait until we enter the current state
while (targetAnim.GetCurrentAnimatorStateInfo(0).fullPathHash != animHash)
{
yield return null;
}
float counter = 0;
float waitTime = targetAnim.GetCurrentAnimatorStateInfo(0).length;
//Now, Wait until the current state is done playing
while (counter < (waitTime))
{
counter += Time.deltaTime;
yield return null;
}
//Done playing. Do something below!
Debug.Log("Done Playing");
}
For a solution specifically for your particular problem with the collision callback function (OnTriggerEnter
), there are two possible ways to do that:
1.Start a coroutine function to play the animation after trigger detection:
void OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "OnTop Detector")
{
Debug.Log("On Top of Platform");
GameObject findGo = GameObject.Find("ThirdPersonController");
GameObject findGo1 = GameObject.Find("Elevator");
findGo.transform.parent = findGo1.transform;
target = GameObject.Find("Elevator");
StartCoroutine(playAnim(target));
}
}
IEnumerator playAnim(GameObject target)
{
Animation anim = target.GetComponent<Animation>();
anim.Play("Up");
//Wait until Up is done Playing the play down
while (anim.IsPlaying("Up"))
{
yield return null;
}
//Now Play Down
anim.Play("Down");
}
OR
2.Make the OnTriggerEnter
function a coroutine(IEnumerator) instead of void
function:
IEnumerator OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "OnTop Detector")
{
Debug.Log("On Top of Platform");
GameObject findGo = GameObject.Find("ThirdPersonController");
GameObject findGo1 = GameObject.Find("Elevator");
findGo.transform.parent = findGo1.transform;
target = GameObject.Find("Elevator");
Animation anim = target.GetComponent<Animation>();
anim.Play("Up");
//Wait until Up is done Playing the play down
while (anim.IsPlaying("Up"))
{
yield return null;
}
//Now Play Down
anim.Play("Down");
}
}
How to wait until animation is finished when using Animator?
Try this
IEnumerator popDownAnimation(string c)
{
animator = GetComponent<Animator>();
animator.Play("Pop Down Animation");
float animationLength = animator.GetCurrentAnimatorStateInfo(0).length;
yield return new WaitForSecondsRealtime(animationLength);
animator.Play("New State");
}
However, like @NotVeryGoodAtThis mentioned, I wouldn't do this in code unless you have a specific reason why you can't make it work using animation events or using parameters within the animator to transition between animation states. Designing your animation using Unity's Animator window and using states, parameters, and transitions will be easier to manage than doing it through code, especially as your animators become more complicated.
Play animation 5 times
Use the for
loop in IEnumerator
to solve the problem. Also make sure you enter the layer number correctly. Here the wave state is repeated 5 times in layer zero.
private IEnumerator PlayAnimInterval(int n)
{
for (int i = 0; i < n; i++)
{
anim.Play("wave", 0, 1);
yield return new WaitForSeconds(anim.GetCurrentAnimatorStateInfo(0).length);
}
}
How to detect Animator Layer?
The animator layer is an array. By adding each layer in the layers section, its index is also added. You can find its code below.
Repeat State Info with Behaviour
In this method you can solve the problem of repetition in any state. Just create a behavior like the one below and just add the number of repetitions. This method also works independently of the layer.
public class Repeat : StateMachineBehaviour
{
public int repeatTime;
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (repeatTime <= 0) return;
repeatTime--;
animator.Play(stateInfo.fullPathHash);
}
}
Wait for an animation to finish in unity3d
Basically you need to do two things for this solution to work:
- Start the animation.
- Wait for the animation to finish before you play next animation.
An example of how this could be done is:
animation.PlayQueued("Something");
yield WaitForAnimation(animation);
And the definition for WaitForAnimation
would be:
C#:
private IEnumerator WaitForAnimation (Animation animation)
{
do
{
yield return null;
} while (animation.isPlaying);
}
JS:
function WaitForAnimation (Animation animation)
{
yield; while ( animation.isPlaying ) yield;
}
The do-while loop came from experiments that showed that the animation.isPlaying
returns false
in the same frame PlayQueued is called.
With a little tinkering you can create a extension method for animation that simplifies this such as:
public static class AnimationExtensions
{
public static IEnumerator WhilePlaying( this Animation animation )
{
do
{
yield return null;
} while ( animation.isPlaying );
}
public static IEnumerator WhilePlaying( this Animation animation,
string animationName )
{
animation.PlayQueued(animationName);
yield return animation.WhilePlaying();
}
}
Finally you can easily use this in code:
IEnumerator Start()
{
yield return animation.WhilePlaying("Something");
}
Source, alternatives and discussion.
How can I wait for the object to end spinning and then play the animation?
In your case you can make your calling IEnumerator
wait until the other one is finished by simply yield
ing it like
...
// executes and at the same time waits for Spin to finish
yield return Spin(3f, rotation);
// called when Spin routine is finished
anim.SetBool("Roll_Anim", true);
Alternatively instead of a third-party tool library like suggested here you could simply add a callback like
IEnumerator Spin(float lerpTime, Quaternion rotation, Action whenDone)
{
float elapsedTime = 0f;
while (elapsedTime <= lerpTime)
{
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, elapsedTime / lerpTime);
elapsedTime += Time.deltaTime;
yield return null;
}
whenDone?.Invoke();
}
and then start the routine either using a lambda expression like
StartCoroutine(Spin(3f, rotation, () =>
{
anim.SetBool("Roll_Anim", true);
}));
or a method call like
private void AfterSpinning()
{
anim.SetBool("Roll_Anim", true);
}
...
StartCoroutine(Spin(3f, rotation, AfterSpinning));
Unity - wait until animation finished
in the animation tab of your animated gameobject create an event at the last frame of the animation, attach the above script to this gameobject, and choose the method you want to run at the end of it
Remove The coroutine and just make a simple method
public void LoadScene()
{
LoadAsync(sceneName, sliderLoadbar, sliderLoadbarText)
}
Related Topics
C# Sending Mails with Images Inline Using Smtpclient
Cannot Close Excel.Exe After Interop Process
How to Hide a Column (Gridview) But Still Access Its Value
How to Modify or Delete Items from an Enumerable Collection While Iterating Through It in C#
How to Deserialize JSON with Duplicate Property Names in the Same Object
Best Practice to Make a Multi Language Application in C#/Winforms
Difference Between MVC 5 Project and Web API Project
Does List<T> Guarantee Insertion Order
How to Call Generic Method with a Given Type Object
How to Copy Part of an Array to Another Array in C#
Why We Need Thread.Memorybarrier()
How to Convert Datatable to JSON String Using JSON.Net
Where's the Datetime 'Z' Format Specifier
Tabcontrol with Close and Add Button
How to Select Text from the Richtextbox and Then Color It
Restrict Access to a Specific Controller by Ip Address in ASP.NET MVC Beta