Arnice123
Arnice123

Reputation: 195

How can I wait for the animation to finish then let the code resume?

I am trying to have an enemy attack the player and the enemy attacks through animation however the method I have to prevent the animation from starting when others are active are not working. The problem is that the method I have is just not working. To be more specific, it doesn't do anything basically like a comment. If there is any code you need I should be able to provide it.

Here is the code:

IEnumerator PlayAnim(Animator anim, string booleanName) 
    {
        anim.SetBool(booleanName, true);
        yield return new WaitForSeconds(anim.GetCurrentAnimatorStateInfo(0).length + anim.GetCurrentAnimatorStateInfo(0).normalizedTime); // I checked and got a value for that number so it should be paused
        anim.SetBool(booleanName, false);
        
    }

In the code above I put a debug at the start and the end of it and when I ran the code they ran at the same second so I know that it doesn't work.

Here is how it is being called:

public void AttackPlayer(GameObject playerPos, Animator anim, NavMeshAgent agent, GameObject self, bool MultiAttack, float inRange, float inView, float AttackRange, bool isBlocking, bool HasSeenPLayer)
    {       

        if (MultiAttack)
        {                      
            MultAttack(playerPos, anim, agent, self, inRange, inView);                    
        }
        else
        {
            anim.SetBool("Attack2", false);
            anim.SetBool("Attack3", false);
            StartCoroutine(PlayAnim(anim, "Attack"));
        }
        
        if (!PlayerPos.FindPlayerPos(AttackRange, playerPos.transform, inView, self, HasSeenPLayer))
        {
            anim.SetBool("Attack", false);
            anim.SetBool("Attack2", false);
            anim.SetBool("Attack3", false);
            state = State.Chase;
        }
    }

    public void MultAttack(GameObject playerPos, Animator anim, NavMeshAgent agent, GameObject self, float inRange, float inView)
    {
        
        if (random == 0) random = Random.Range(1, 5);

        if (random == 1)
        {            
            StartCoroutine(PlayAnim(anim, "Attack"));
            random = 0;
            
            return;
        }

        if (random == 2)
        {
            if (HasParameter("Attack2", anim))
            {                
                StartCoroutine(PlayAnim(anim, "Attack2"));
                random = 0;
                
                return;
            }
            
            StartCoroutine(PlayAnim(anim, "Attack"));
            random = 0;
            
            return;
        }

        if (random == 3)
        {            
            if (alk != null)
            {                  
                alk.particle.gameObject.SetActive(true);
                alk.particle.Play();                
            }
                        
            StartCoroutine(AlkAnim(anim, "Attack3"));
            random = 0;
            
            return;
        }

        if (random == 4)
        {            
            BlockPlayer(playerPos, anim, agent, inRange, inView, self);
            random = 0;
            
            return;
        }

        
        StartCoroutine(PlayAnim(anim, "Attack"));
        random = 0;
        
        return;

    }

    IEnumerator AlkAnim(Animator anim, string booleanName)
    {
        anim.SetBool(booleanName, true);
        yield return new WaitForSeconds(anim.GetCurrentAnimatorStateInfo(0).length + anim.GetCurrentAnimatorStateInfo(0).normalizedTime);
        anim.SetBool(booleanName, false);
        if (alk != null)
        {
            alk.particle.Stop();
            alk.particle.gameObject.SetActive(false);
            random = 0;
        }
    }

    public static bool HasParameter(string paramName, Animator animator)
    {
        foreach (AnimatorControllerParameter param in animator.parameters)
        {
            if (param.name == paramName)
                return true;
        }
        return false;
    }    

void Start()
{
    StartCoroutine(GetGood());
}

 IEnumerator GetGood()
    {        
        TtF.ChoseChasingWhatStateToAttackPlayer(agent, Player_pos.player, self, anim, MultiAttack, inRange, inView, AttackRange, isBlocking, hasSeenPlayer);
        
        yield return new WaitForSeconds(0.5f); 
        StartCoroutine(GetGood());
    }

Upvotes: 5

Views: 291

Answers (1)

derHugo
derHugo

Reputation: 90862

I think your first approach would work theoretically. The only "issue" is that even though you already set the flag in the animator component the animator is one of the last things being executed within a frame (see Execution Order of Events). So I think you just would have to give it the time to actually switch the state.

You could e.g. try to first use a yield return new WaitForEndOfFrame (); before starting to wait for the length of the current state.


Another approach could be Animator Events. You could place sich an event at the very end of your animation and simply let it call a dedicated method.

Upvotes: 1

Related Questions