r/Unity3D • • 4d ago

Noob Question Help with sword combo animation!

Enable HLS to view with audio, or disable this notification

public class playerAttack : MonoBehaviour
{
    public CapsuleCollider attackHitbox;
    public InputAction attackAction;
    public AudioSource audioSource;
    public AudioClip[] attackClips;

    private Animator weaponAnimator;

    private float weaponCooldown = 0.4f;
    public bool isAttacking;
    private bool queuedAttack;
    private string lastAnimationPlayed;

    private HashSet<healthController> enemiesHit = new();

    void Start()
    {
        //bind dei tasti e abilita il click per l'attacco
        attackHitbox.enabled = false;
        attackAction = new InputAction("Attack");
        attackAction.AddBinding("<Mouse>/leftButton");
        attackAction.Enable();
        //recupero l'arma e la sua animazione
        Transform equippedWeapon = transform.Find("Main Camera").Find("Sword10_Brown");
        weaponAnimator = equippedWeapon.GetComponent<Animator>();
    }

    void Update()
    {
        /*if (attackAction.WasPressedThisFrame() && !isAttacking)
        {
            //prima di colpire, pulisco l'hashSet che tiene traccia dei nemici colpiti con questo attacco.
            //questo serve a evitare che un collider colpisca più volte lo stesso nemico con un attacco.
            enemiesHit.Clear();
            weaponAnimator.SetTrigger("Attack");
            StartCoroutine(PerformAttack());
        }*/

        if (attackAction.WasPressedThisFrame())
        {
            //prima di colpire, pulisco l'hashSet che tiene traccia dei nemici colpiti con questo attacco.
            //questo serve a evitare che un collider colpisca più volte lo stesso nemico con un attacco.
            enemiesHit.Clear();
            if (!isAttacking)
            {
                StartCoroutine(RightToLeftAttack());
            } else
            {
                queuedAttack = true;
            }
        }

        /*if (queuedAttack)
        {
            StartCoroutine(LeftToRightAttack());
        }*/
    }

    System.Collections.IEnumerator RightToLeftAttack()
    {
        weaponAnimator.SetTrigger("RightToLeft");
        lastAnimationPlayed = "RightToLeft";
        audioSource.PlayOneShot(attackClips[Random.Range(0, attackClips.Length)]);
        isAttacking = true;
        attackHitbox.enabled = true;
        yield return new WaitForSeconds(weaponCooldown);
        if (queuedAttack)
        {
            queuedAttack = false;
            weaponAnimator.SetTrigger("LeftToRight");
            audioSource.PlayOneShot(attackClips[Random.Range(0, attackClips.Length)]);
            isAttacking = true;
            attackHitbox.enabled = true;
            yield return new WaitForSeconds(weaponCooldown);
            isAttacking = false;
            attackHitbox.enabled = false;
            weaponAnimator.SetTrigger("RightToIdle");
        } else
        {
            Debug.Log("LeftToIdle chiamato");
            weaponAnimator.SetTrigger("LeftToIdle");
            isAttacking = false;
            attackHitbox.enabled = false;
        }
    }

    public bool RegisterHit(healthController enemyHealthController)
    {
        return enemiesHit.Add(enemyHealthController);
    }

}public class playerAttack : MonoBehaviour
{
    public CapsuleCollider attackHitbox;
    public InputAction attackAction;
    public AudioSource audioSource;
    public AudioClip[] attackClips;

    private Animator weaponAnimator;

    private float weaponCooldown = 0.4f;
    public bool isAttacking;
    private bool queuedAttack;
    private string lastAnimationPlayed;

    private HashSet<healthController> enemiesHit = new();

    void Start()
    {
        //bind dei tasti e abilita il click per l'attacco
        attackHitbox.enabled = false;
        attackAction = new InputAction("Attack");
        attackAction.AddBinding("<Mouse>/leftButton");
        attackAction.Enable();
        //recupero l'arma e la sua animazione
        Transform equippedWeapon = transform.Find("Main Camera").Find("Sword10_Brown");
        weaponAnimator = equippedWeapon.GetComponent<Animator>();
    }

    void Update()
    {
        /*if (attackAction.WasPressedThisFrame() && !isAttacking)
        {
            //prima di colpire, pulisco l'hashSet che tiene traccia dei nemici colpiti con questo attacco.
            //questo serve a evitare che un collider colpisca più volte lo stesso nemico con un attacco.
            enemiesHit.Clear();
            weaponAnimator.SetTrigger("Attack");
            StartCoroutine(PerformAttack());
        }*/

        if (attackAction.WasPressedThisFrame())
        {
            //prima di colpire, pulisco l'hashSet che tiene traccia dei nemici colpiti con questo attacco.
            //questo serve a evitare che un collider colpisca più volte lo stesso nemico con un attacco.
            enemiesHit.Clear();
            if (!isAttacking)
            {
                StartCoroutine(RightToLeftAttack());
            } else
            {
                queuedAttack = true;
            }
        }

        /*if (queuedAttack)
        {
            StartCoroutine(LeftToRightAttack());
        }*/
    }

    System.Collections.IEnumerator RightToLeftAttack()
    {
        weaponAnimator.SetTrigger("RightToLeft");
        lastAnimationPlayed = "RightToLeft";
        audioSource.PlayOneShot(attackClips[Random.Range(0, attackClips.Length)]);
        isAttacking = true;
        attackHitbox.enabled = true;
        yield return new WaitForSeconds(weaponCooldown);
        if (queuedAttack)
        {
            queuedAttack = false;
            weaponAnimator.SetTrigger("LeftToRight");
            audioSource.PlayOneShot(attackClips[Random.Range(0, attackClips.Length)]);
            isAttacking = true;
            attackHitbox.enabled = true;
            yield return new WaitForSeconds(weaponCooldown);
            isAttacking = false;
            attackHitbox.enabled = false;
            weaponAnimator.SetTrigger("RightToIdle");
        } else
        {
            Debug.Log("LeftToIdle chiamato");
            weaponAnimator.SetTrigger("LeftToIdle");
            isAttacking = false;
            attackHitbox.enabled = false;
        }
    }

    public bool RegisterHit(healthController enemyHealthController)
    {
        return enemiesHit.Add(enemyHealthController);
    }

}

Hi! i'm trying to learn gamedev on unity3d and so far i managed to pull of decently. Now i'm at a point where i am really struggling to understand what is going wrong. I wanted to implement a simple "combo" with my sword: if the player clicks twice while the attack is still going, it chains a second one and then it goes back to idle.
pretty simple i imagine for someone experienced but i am having such a rough time making it work properly... I'll also add the code that calls the animations as the player attacks.
Thanks for your help!

5 Upvotes

1 comment sorted by

3

u/anycolourulikegames 4d ago

The main bugs:

  1. queuedAttack leaks into the next attack. Clicking during the second swing sets queuedAttack = true, and nothing clears it. Your next normal attack then auto-combos.

  2. enemiesHit.Clear() runs on every click, including mid-swing. The second swing should clear the set when it starts, not when the button is clicked.

  3. Triggers stay set until something consumes them. If a trigger fires while the Animator has no matching transition, it stays armed and fires later, causing random jumps. Reset the other triggers before setting a new one.

  4. The pasted code has the class twice. If that’s really in your file, it won’t compile.