0
\$\begingroup\$

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!

\$\endgroup\$
0
\$\begingroup\$

You'll have to forgive me for using the answer field for a less than totally certain answer -- but the coroutine FirstAttack looks like its logic shouldn't repeat, so if you're getting the animation looping, what are the conditions in your animator for the animation to run?

As it stands, when FirstAttack begins it sets combo to 1 and state to attack. This does not change until the attack either times out or combo changes to 2 which triggers the new attack.

How are the attacks triggered in the animator? If the only condition for the first attack is that combo is 1 -- which remains true for the entire duration -- then it will loop. Have you ensured the wrap mode / play mode is set to 'play once' and not to loop?

\$\endgroup\$
  • \$\begingroup\$ I am using an integer, comboCounter, that is originally set to 0. If I press the hit button, it updates to 1 and starts the animation for the first attack and if I press it again during the opening for the second attack it updates to 2. In the animator I keep seeing the value 1, which is ok, but it's like the SetInteger function keeps checking every frame. \$\endgroup\$ – FSic Jun 11 at 5:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.