Enemy cancels attack when I move

Running into an issue where the enemy cancels its bow attack if I move during it, basically if I stand still its fine but if I move it starts the animation but cancels before the animation event hits. I’m assuming it’s an issue with the action scheduler but can’t find where exactly the issue is. I’ll share my actionscheduler, fighter and aicontroller code.

using RPG.Core;
using RPG.Movement;
using UnityEditor;
using UnityEngine;

namespace RPG.Combat
{
    public class Fighter : MonoBehaviour, IAction
    {
        // Weapon Properties
        [SerializeField] private Weapon defaultWeapon = null;

        private Weapon currentWeapon = null;

        [SerializeField]
        private Transform leftHandTransform = null;

        [SerializeField]
        private Transform rightHandTransform = null;

        // Components
        private Mover mover;

        private ActionScheduler scheduler;
        private Animator anim;

        // Enemy
        private Health target;

        // IAction Name
        public string Name => "Fighter";

        // Variables
        private float timeSinceLastAttack = Mathf.Infinity;

        private void Awake()
        {
            mover = GetComponent<Mover>();
            scheduler = GetComponent<ActionScheduler>();
            anim = GetComponent<Animator>();
        }

        private void Start()
        {
            EquipWeapon(defaultWeapon);
        }

        private void Update()
        {
            timeSinceLastAttack += Time.deltaTime;

            // Return if no target
            if (!target || target.IsDead()) return;

            // Check if we are in range
            if (target && !GetIsInRange())
            {
                mover.MoveTo(target.transform.position, 1f);
            }
            else
            {
                mover.Cancel();
                AttackBehaviour();
            }
        }

        public void EquipWeapon(Weapon weapon)
        {
            currentWeapon = weapon;
            weapon.Spawn(rightHandTransform, leftHandTransform, anim);
        }

        private void AttackBehaviour()
        {
            // Look at target
            transform.LookAt(target.transform);
            if (timeSinceLastAttack >= currentWeapon.GetCooldown())
            {
                // Set animation trigger and cooldown
                anim.ResetTrigger("stopAttack");
                anim.SetTrigger("attack");
                timeSinceLastAttack = 0f;
            }
        }

        private bool GetIsInRange()
        {
            if (target)
                return Vector3.Distance(target.transform.position, transform.position) <= currentWeapon.GetRange();
            else return false;
        }

        public bool CanAttack(GameObject combatTarget)
        {
            return combatTarget && combatTarget.TryGetComponent(out Health test) ? !test.IsDead() : false;
        }

        // Start Attack through scheduler
        public void Attack(GameObject combatTarget)
        {
            scheduler.StartAction(this);
            target = combatTarget.GetComponent<Health>();
        }

        public void Cancel()
        {
            anim.ResetTrigger("attack");
            anim.SetTrigger("stopAttack");
            target = null;
            GetComponent<Mover>().Cancel();
        }

#if UNITY_EDITOR

        private void OnDrawGizmos()
        {
            float weaponAngle = 30f;
            Vector3 left = Quaternion.AngleAxis(-weaponAngle / 2f, Vector3.up) * transform.forward;
            Handles.color = new Color(1f, 0f, 0f, 0.1f);
            Handles.DrawSolidArc(transform.position + Vector3.up, Vector3.up, left, weaponAngle, currentWeapon.GetRange());
            Handles.color = Color.red;
            Handles.DrawWireArc(transform.position + Vector3.up, Vector3.up, left, weaponAngle, currentWeapon.GetRange());
        }

#endif

        // Animation Event
        private void Hit()
        {
            if (target)
            {
                if (currentWeapon.HasProjectile())
                {
                    currentWeapon.Fire(rightHandTransform, leftHandTransform, target);
                }
                else
                {
                    target.TakeDamage(currentWeapon.GetDamage());
                }
            }
        }
        private void Shoot()
        {
            Hit();
        }    
    }
}
using RPG.Combat;
using RPG.Core;
using RPG.Movement;
using System;
using UnityEngine;
using UnityEngine.AI;

namespace RPG.Control
{
    public class AIController : MonoBehaviour
    {
        [Range(0f, 1f)]
        [SerializeField] private float patrolSpeedFraction = 0.2f;
        [SerializeField] private float chaseDistance = 5f;
        [SerializeField] private float suspicionTime = 3f;

        private GameObject player;
        private Fighter fighter;
        private Health health;
        private Mover mover;

        // Guard
        [SerializeField] private PatrolPath patrolPath;
        [SerializeField] private float waypointTolerance = 1f;
        private int currentWaypointIndex = 0;
        private Vector3 guardPosition;
        private float timeSinceLastSawPlayer = Mathf.Infinity;
        private float timeSinceArrivedAtWaypoint = Mathf.Infinity;
        private bool lookedAround = false;

        private void Awake()
        {
            fighter = GetComponent<Fighter>();
            health = GetComponent<Health>();
            mover = GetComponent<Mover>();
        }

        private void Start()
        {
            player = GameObject.FindWithTag("Player");
            guardPosition = transform.position;
        }

        private void Update()
        {
            if (health.IsDead()) return;

            if (InAttackRange() && fighter.CanAttack(player))
            {
                lookedAround = false;
                AttackBehaviour();
            }
            else if (timeSinceLastSawPlayer < suspicionTime)
            {
                SuspicionBehaviour();
            }
            else
            {
                lookedAround = false;
                PatrolBehaviour();
            }

            UpdateTimers();
        }

        private void UpdateTimers()
        {
            timeSinceLastSawPlayer += Time.deltaTime;
            timeSinceArrivedAtWaypoint += Time.deltaTime;
        }

        private void AttackBehaviour()
        {
            timeSinceLastSawPlayer = 0;
            fighter.Attack(player);
        }

        private void SuspicionBehaviour()
        {
            if (lookedAround == false && GetComponent<NavMeshAgent>().velocity.magnitude <= 0.1f)
            {
                GetComponent<Animator>().SetTrigger("lookAround");
                lookedAround = true;
            }
            GetComponent<ActionScheduler>().CancelCurrentAction();
        }
        private void PatrolBehaviour()
        {
            Vector3 nextPosition = guardPosition;
            if (patrolPath)
            {
                if (AtWaypoint())
                {
                    timeSinceArrivedAtWaypoint = 0;
                    CycleWaypoint();
                }
                nextPosition = GetCurrentWaypoint();
            } 
            if (!patrolPath || timeSinceArrivedAtWaypoint > patrolPath.GetWaypointDwellTime(currentWaypointIndex))
            {
                mover.StartMoveAction(nextPosition, patrolSpeedFraction);
            }
        }
        private bool AtWaypoint()
        {
            return Vector3.Distance(transform.position, GetCurrentWaypoint()) < waypointTolerance;
        }
        private Vector3 GetCurrentWaypoint()
        {
            return patrolPath.GetWaypoint(currentWaypointIndex);
        }
        private void CycleWaypoint()
        {
            currentWaypointIndex = patrolPath.GetNextIndex(currentWaypointIndex);
        }
        private void GuardBehaviour()
        {
            mover.StartMoveAction(guardPosition, patrolSpeedFraction);
        }

        private bool InAttackRange()
        {
            return Vector3.Distance(player.transform.position, transform.position) < chaseDistance;
        }

        private void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.white;
            Gizmos.DrawWireSphere(transform.position, chaseDistance);
        }
    }
}
using UnityEngine;

namespace RPG.Core
{
    public class ActionScheduler : MonoBehaviour
    {
        IAction currentAction;
        public void StartAction (IAction action) 
        {
            // Check if action is already running
            if (currentAction == action) return;

            // Cancel current action if possible
            if (currentAction != null) 
            {
               currentAction.Cancel();
            }

            // Set new action
            currentAction = action;
        }
        public void CancelCurrentAction()
        {
            StartAction(null);
        }
    }
}

Seems to be working now but I haven’t actually changed the code, might’ve been an issue between chase radius and weapon range as I was messing with those a bit?

Quite probably.

The behavior you’re describing is by design. If you are no longer in range to get hit, then the enemy should be cancelling the attack and chasing you instead.

Privacy & Terms