Hi all I’m pretty new to Unity (have some experience with C#) and would like to ask you for an advice on the topic mentioned in the title. I’m coming from a JS background, so I’m familiar with the promises and how they work.
My intention is to implement a similar pattern in the game I’m creating.
a/ I would like to play a sequence of animations in order (I know that I can use the animator and make transitions there, but there are different things in the project that are not part of the topic). At the end I’m aiming for:
await Play("show");
await Play("jump");
await Play("walk");
async void Play(string anim)
{
await animator.Play(anim);
}
public void OnAnimPlayEnd()
{
// Emitted on the last frame of the active animation
}
The point here is that I don’t understand how can I “resolve” the await in Play from OnAnimPlayEnd. Maybe I should use a different approach?
b/ I have a public method named Move which is called once. At that point I start moving an object on each FixedUpdate. Again here a would like to call await Move() from outside and wait for it to finish until I resume with the next line of code
Also I’ve came across a post in the forum from I user mentioning that async/await is not working for Android. Is that correct based on you experience? I’m sorry if I misled you.
Excuse me for the long post. I would really appreciate your help.
Thank you.
Animator wasn’t supposed to work in async context, like the rest of the Unity, you can’t await animations like that, sadly.
If you know the length of your animations, then you can simply use timers or coroutines.
Another option is to add events on frame timeline of specific animation which will call some function on your GameObject.
If you need more flexible and code based approach you can read about StateMachineBehaviours class which can be derived and added to animator state. There are callbacks OnEnter, OnUpdate and OnExit, you can add your event and subcribe to it via animator.GetBehaviour().
The only way I know of for a script to reliably detect what an animator is doing is to use animation events. This unfortunately requires you to manually create a separate event for each moment you want to detect. Presumably you could write a custom await-able function that returns when the event fires, but this would just be syntactic sugar, and you’d still need a separate function for each event.
(At one point I tried to make a script that would synchronize with animations just by waiting a length of time equal to the animation’s duration, but this turned out to be noticeably inaccurate. I think because of blending between animations.)
Thank you both.
I understand that the most reliable way of detecting an animation end is emitting an event on the last frame. This is what I actually do. I have public voidOnAnimPlayEnd which is called on the animation’s last frame. From that point onwards I want to handle everything through async/await. What I don’t understand is how can I link the end of the animation (i.e. OnAnimPlayEnd) with the async voidPlay method that has been called initially for starting the animation. With other words how can I “release” the await once OnAnimPlayEnd has been called from the animator.
Currently my code is entirely structured by using event. I.e. once OnAnimPlayEnd is called an event is emitted up the chain for anyone who have subscribed and so on. This requires a lot of event subscription/unsubscription which makes the code unreadable and I think can be avoided with just awaiting the current line of code.
You can make your event function set some sort of variable that indicates that it has been called, and you can write an async function that does Task.Delay in a loop until that variable has been set.
(I’m not arguing this is a good option. But it’s an option.)