Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] Animação Enemy_Die e Enemy_Hurt não são executadas

Acredito que esses são os Scripts envolvidos:

Health:
using System;
using UnityEngine;

public class Health : MonoBehaviour
{
    [SerializeField] private int lives;

    public event Action OnDead;
    public event Action OnHurt;

    public void TakeDamage()
    {
        lives--;
        HandleDamageTaken();
    }

    private void HandleDamageTaken()
    {
        if (lives <= 0)
        {
            OnDead?.Invoke();
        }
        else
        {
            OnHurt?.Invoke();
        }
    }
}
BaseEnemy:
using System.Collections;
using UnityEngine;

[RequireComponent(typeof(Animator), typeof(AudioSource))]
public abstract class BaseEnemy : MonoBehaviour
{
    protected Animator _Animator;
    protected AudioSource _AudioSource;
    protected Health _Health;

    protected bool canAttack = true;

    protected virtual void Awake()
    {
        _Animator = GetComponent<Animator>();
        _AudioSource = GetComponent<AudioSource>();
        _Health = GetComponent<Health>();

        _Health.OnHurt += PlayHurtAnimation;
        _Health.OnDead += HandleDeath;
    }

    protected abstract void Update();

    private void PlayHurtAnimation() => _Animator.SetTrigger("Hurt");
    
    private void HandleDeath()
    {
        canAttack = false;
        GetComponent<BoxCollider2D>().enabled = false;
        _Animator.SetTrigger("Dead");
        StartCoroutine(DestroyEnemy(2));
    }

    private IEnumerator DestroyEnemy(int time)
    {
        yield return new WaitForSeconds(time);
        Destroy(this.gameObject);
    }
}
MeleeEnemy:
using UnityEngine;

public class MeleeEnemy : BaseEnemy
{
    [Header("Attack properties")]
    [SerializeField] private Transform detectPosition;
    [SerializeField] private Vector2 detectBoxSize;
    [SerializeField] private LayerMask playerLayer;
    [SerializeField] private float attackCooldown;
    
    private float cooldownTimer;

    protected override void Update()
    {
        cooldownTimer += Time.deltaTime;
        VerifyCanAttack();
    }

    private void VerifyCanAttack()
    {
        if (cooldownTimer < attackCooldown || canAttack == false) return;
        if (PlayerInSight())
        {
            _Animator.SetTrigger("Attack");
            AttackPlayer();
        }
    }

    private void AttackPlayer()
    {
        cooldownTimer = 0;
        if (CheckPlayerInDetectArea().TryGetComponent(out Health playerHealth))
        {
            print("Making player take damage");
            playerHealth.TakeDamage();
        }
    }

    private Collider2D CheckPlayerInDetectArea()
    {
        return Physics2D.OverlapBox(detectPosition.position, detectBoxSize, 0f, playerLayer);
    }

    private bool PlayerInSight()
    {
        Collider2D playerCollider = CheckPlayerInDetectArea();
        return playerCollider != null;
    }
    
    private void OnDrawGizmos()
    {
        if (detectPosition == null) return;
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(detectPosition.position, detectBoxSize);
    }
}

Evento na animação de ataque:

Método do ataque do jogador:

    private void Attack()
    {
        Collider2D[] hittedEnemies = Physics2D.OverlapCircleAll(attackPosition.position, attackRange, attackLayer);
        print("Making enemy take damage");
        print(hittedEnemies.Length);

        foreach (Collider2D hittedEnemy in hittedEnemies)
        {
            print("Checking enemy");
            if (hittedEnemy.TryGetComponent(out Health enemyHealth))
            {
                print("Getting damage");
                enemyHealth.TakeDamage();
            }
        }
    }

Scripts anexado ao Inimigo:

Tentei achar oque era mas não conseguir, Mas o código é praticamente o mesmo da aula. Por isso não entendi onde está o erro.

2 respostas

Quando eu fiz o exercício deixado na aula para a execução das animação 'Enemy_Die' e 'Enemy_Hurt' eu não tinha feito direto no 'EnemyBase'. Eu tinha criado um script de animação para inimigos e atribuído ao gameObject do inimigo

using UnityEngine;

public class EnemyAnimation : MonoBehaviour
{
    private Animator _Animator;
    private Health _EnemyHealth;

    void Awake()
    {
        _Animator = GetComponent<Animator>();
        _EnemyHealth = GetComponent<Health>();

        _EnemyHealth.OnHurt += () => SetTriggerAnimation("Hurt");
        _EnemyHealth.OnDead += () => SetTriggerAnimation("Dead");
    }

    public void SetTriggerAnimation(string triggerName)
    {
        _Animator.SetTrigger(triggerName);
    }
}

e acionava o método 'HandleDeath()' a partir de um evento na animação de morte que estava no script 'MeleeEnemy'

    private void HandleDeath()
    {
        canAttack = false;
        GetComponent<BoxCollider2D>().enabled = false;
        Destroy(this.gameObject, 2);
        // No caso eu não tinha feito uma corrotina
    }
solução!

Encontrei o erro!

  • O Erro estava na transição da animação de ataque que estava saindo antes de ativar o evento de ataque!

  • Percebi isso quando trouxe o evento mais para o começo da animação e achei estranho que so funcionava quando o evento estava mais para o início da animação.

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

  • Olhei a configuração da transição de saída e o 'Exit Time' estava com valor muito baixo. Coloquei o 'Exit time' em 1segundo para dar tempo da animação ser toda executada e pegar o evento do ataque. Insira aqui a descrição dessa imagem para ajudar na acessibilidade

  • para garantir que não aconteça mais isso olhei todas as transições de animações com o 'Has Exit Time' Habilitado.
Agora esta funcionando corretamente ^-^

Insira aqui a descrição dessa imagem para ajudar na acessibilidade