Unity2D: Avoid attack animation looping during combo

by FSic   Last Updated June 10, 2019 18:13 PM

I am trying to implement a combo system in my Unity project. I started with a coroutine to call a single attack and it goes relatively smoothly, the problem occurs when I try to modify said coroutine in order to open a time interval in which the player has the chance to click again in order to perform the second attack of the combo, the animation of the first attack keeps looping for the whole duration of the coroutine, unless I manage to connect the second attack, in that case the second animation gets triggered without any problems. Here is the concerned script:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityStandardAssets.CrossPlatformInput;
    using UnityEngine.SceneManagement;

    public enum PlayerState {
        walk,
        attack,
        interact,
        dash,
        stagger
    }

    public class Player_Base : MonoBehaviour {


        //Basic parameters
        Rigidbody2D myRigidBody; 
        public static Transform playerPos;
        public PlayerState currentState;
        Animator myAnimator;
        public HealthManager myStatus;
        private bool isAlive = true;

        //Movement parameters
        [SerializeField] float moveSpeed = 3f; 
        public Vector2 moveInput;
        private bool isMoving;

        //Combat parameters
        private int comboCounter = 0;
        private float comboTimer = 0;


        // Use this for initialization
        void Start()
        {
            currentState = PlayerState.walk;//Initial default state of the player
            myRigidBody = GetComponent<Rigidbody2D>();
            myAnimator = GetComponent<Animator>();
            myAnimator.SetFloat("MoveX", 0);
            myAnimator.SetFloat("MoveY", -1);
            myStatus = GameObject.FindObjectOfType<HealthManager>();
        }

        // Update is called once per frame
        void Update()
        {
            moveInput = Vector2.zero;
            moveInput.x = Input.GetAxisRaw("Horizontal");
            moveInput.y = Input.GetAxisRaw("Vertical");
            if (!isAlive)
            {
                return;
            }
            else {
                if (currentState == PlayerState.walk)           {
                    if (moveInput != Vector2.zero)
                    {
                        Move();
                        myAnimator.SetFloat("MoveX", moveInput.x);
                        myAnimator.SetFloat("MoveY", moveInput.y);
                        myAnimator.SetBool("isMoving", true);
                    }
                    else {
                        myAnimator.SetBool("isMoving", false);
                    }
                }

                if (Input.GetKeyDown(KeyCode.Mouse0) && currentState != PlayerState.attack)//second clause because i do not want to indefinitely attack every frame
                {
                    StartCoroutine(FirstAttack());
                }
        }

        public void Move()
        {
            moveInput.Normalize();
            myRigidBody.MovePosition(myRigidBody.position + moveInput * moveSpeed * Time.deltaTime);
            //If i want to work with the velocity vector: i have to use rb.velocity, not just taking the xplatinput times movespeed
        }

        public void MoveOnAnimation(int xMove, int yMove, float displacement)
        {
            moveInput.x = xMove;
            moveInput.y = yMove;
            moveInput.Normalize();
            myRigidBody.MovePosition(myRigidBody.position + moveInput * displacement * Time.deltaTime);
        }

        private IEnumerator FirstAttack() {

            //Start Attack
            comboCounter = 1;
            myAnimator.SetInteger("comboSequence", comboCounter);
            currentState = PlayerState.attack;



            yield return new WaitForSeconds(AttackTemplate.SetDuration(2f) - comboTimer);
            comboTimer = AttackTemplate.SetComboTimer(1.5f);
            //Interval for combo chain
                while (comboTimer >= 0)
            {

                comboTimer -= Time.deltaTime;
                if (Input.GetKeyDown(KeyCode.Mouse0))
                {
                    Debug.Log("Chained");
                    StartCoroutine(SecondAttack());
                    StopCoroutine(FirstAttack());
                }
                yield return null;
            }
//Combo not triggered
            comboCounter = 0;
            myAnimator.SetInteger("comboSequence", comboCounter);
            //yield return new WaitForSeconds(AttackTemplate.SetDuration(1f));
            currentState = PlayerState.walk;

        }

        private IEnumerator SecondAttack()
        {

            comboCounter = 2;
            myAnimator.SetInteger("comboSequence", comboCounter);
            currentState = PlayerState.attack;
            yield return null;

            //if combo not triggered:
            yield return new WaitForSeconds(AttackTemplate.SetDuration(1f));
            comboCounter = 0;
            myAnimator.SetInteger("comboSequence", comboCounter);

            currentState = PlayerState.walk;

        }

    }

The coroutine SecondAttack() keeps the logic for the single attack, whereas FirstAttack() has a while loop that simply reduces the time interval and eventually starts the second attack. I have noticed that in the animator window the transition towards the first attack animation keeps reactivating, as if constantly checking the value of the parameter that triggers it.

Has this happened to anybody else? All kinds of hints will be very much appreciated and sorry if my script is not too tidy!



Related Questions


Updated October 03, 2018 22:13 PM

Updated May 11, 2019 04:13 AM

Updated August 05, 2016 08:05 AM

Updated July 19, 2017 20:13 PM

Updated November 20, 2017 22:13 PM