Need help with FPS Shooting AI Behaviour script

Okay, all I have now is an AI that can move and rotate to find player position (using nav mesh agent) and playing running animation, can stop and play shooting animation if the player is in its shooting range. And here is my problem:

Despite the shooting animation is playing, the AI is not actually shooting at all. I have some timer variables to make AI raycast shooting look like an automatic rifle behaviour (10 bullets/1s for example) but the problem is that the countdown timer is not decreasing. Every time I move the player and then if the AI found the player again, the countdown decreases for about 0,0001 second and then stops. (AI still moves if I move or stays at shooting position and plays shooting animation if the player is not moving).

Can someone take a look at my script and tell me if I’m missing something. Thank you for taking your time to read my question. Here is the script:

public class AIBehaviour : MonoBehaviour
{

    public enum State
    {
        FindingTarget,
        Shooting
    }

    public State state = State.FindingTarget;

    public int damage;

    public float moveSpeed;

    public float delayToShoot;

    [Tooltip("The time to check if Player is still there at the position being shot")]
    public float nextTimeToSearch;

    public Transform gunTip;

    private Transform _target;

    private NavMeshAgent _agent;

    private Animator _anim;

    private bool _targetInRange;

    [SerializeField] private float _countdownToSearch;

    [SerializeField] private float _countdownToShoot;

    void Start()
    {
        _agent = GetComponent<NavMeshAgent>();
        _target = PlayerManager.instance.player.transform;
        _anim = GetComponentInChildren<Animator>();
        state = State.FindingTarget;
        _agent.speed = moveSpeed;
        _countdownToSearch = nextTimeToSearch;
        _countdownToShoot = delayToShoot;
    }

    private void Update()
    {
        // if there is target to find at all
        if (_target != null)
        {
            // find target
            if (!_targetInRange)
            {
                FindTarget();
            }

            if (state == State.Shooting && _targetInRange)
            {
                // check if player is still at the being shot position
                if (_countdownToSearch <= 0)
                {
                    _countdownToSearch = nextTimeToSearch;
                    RaycastHit hit;
                    if (Physics.Raycast(gunTip.position, gunTip.forward, out hit, Mathf.Infinity))
                    {
                        if (!hit.transform.gameObject.CompareTag("Player"))
                        {
                            Debug.Log("Player has moved!");
                            // then find player again
                            _targetInRange = false;
                            FindTarget();
                        }
                        else return;
                    }
                }
                else _countdownToSearch -= Time.deltaTime;

            }

            else if (state == State.FindingTarget && _targetInRange && state != State.Shooting)
            {
                Shoot();
                _anim.SetBool("Fire", true);
            }
        }
        else
        {
            Debug.LogWarning("Currently there is no player in the scene");
        }
    }

    void FindTarget()
    {
        state = State.FindingTarget;

        _agent.speed = moveSpeed;
        _agent.SetDestination(_target.position);
        _anim.SetFloat("Speed", _agent.speed);
        _anim.SetBool("Fire", false);

        Quaternion lookRotation = Quaternion.LookRotation(_target.position - transform.position);
        transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5f);

        RaycastHit raycasthit;
        if (Physics.Raycast(gunTip.position, gunTip.forward, out raycasthit, Mathf.Infinity))
        {
            if (raycasthit.transform.gameObject.tag == "Player")
            {
                _targetInRange = true;
                Debug.Log("Found Player!");
            }
            else
            {
                _targetInRange = false;
                _agent.isStopped = false;
                return;
            }
        }
    }

    void Shoot()
    {
        state = State.Shooting;
        Debug.Log("Fire!");
        _agent.isStopped = true;

        transform.LookAt(_target);

        if (_countdownToShoot <= 0)
        {
            RaycastHit hit;
            if (Physics.Raycast(gunTip.position, gunTip.forward, out hit, Mathf.Infinity))
            {
                PlayerCharacter playerHealth = hit.transform.gameObject.GetComponent<PlayerCharacter>();
                if (playerHealth != null)
                {
                    Debug.Log("Player is being shot!");
                    playerHealth.Hurt(damage);
                }
            }
            _countdownToShoot = delayToShoot;
        }
        else _countdownToShoot -= Time.deltaTime;
    }
}

I FINALLY GOT IT TO WORK!

As it turned out that I myself made a mountain out of a molehill when using enum for a just simple finite-state machine. I tested the script without with the enum states and it turned out that, the enum state is acting like a bool. For example below lines of code will update the target position for the agent to move

if (_target != null)
        {
            FindTarget();
        }

while this will only get the position once and will not update the new position of the target

if (_target != null && state!=State.FindingTarget)
        {
            FindTarget();
        }

So I got rid of all the enum states and now I’m having a simple AI FPS behaviour that I want. Simple FSM. AI finds, moves and rotates to target. If found target then it aims. Then after aiming for desired seconds, it shoots. Then if the player moved ouf of shooting range or out of sight, it returns to find target. That’s it. Here is the updated script. The PlayerCharacter is a script on player which contains a public function for AI to call and damage the player.

public class AIBehaviour : MonoBehaviour
{
    public int damage;

    public float moveSpeed;

    public float delayToShoot;

    [Tooltip("The time to check if Player is still there at the position being shot")]
    public float nextTimeToSearch;

    public float fireRate;

    private float _nextTimeToFire;

    public Transform gunTip;

    private Transform _target;

    private NavMeshAgent _agent;

    private Animator _anim;

    [SerializeField] private float _countdownToSearch;


    void Start()
    {
        _agent = GetComponent<NavMeshAgent>();
        _target = PlayerManager.instance.player.transform;
        _anim = GetComponentInChildren<Animator>();
        _agent.speed = moveSpeed;
        _countdownToSearch = nextTimeToSearch;
        _nextTimeToFire = 0;
    }

    private void Update()
    {
        if (_target != null)
        {
            FindTarget();
        }
    }

    void FindTarget()
    {
        _agent.speed = moveSpeed;
        _agent.SetDestination(_target.position);

        _anim.SetFloat("Speed", _agent.speed);
        _anim.SetBool("Fire", false);

        Quaternion lookRotation = Quaternion.LookRotation(_target.position - transform.position);
        transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5f);

        RaycastHit raycasthit;
        if (Physics.Raycast(gunTip.position, gunTip.forward, out raycasthit, Mathf.Infinity))
        {
            if (raycasthit.transform.gameObject.tag == "Player")
            {
                Debug.Log("Found Player!");
                StartCoroutine(Aim());
            }
            else
            {
                _agent.isStopped = false;
                return;
            }
        }
    }

    IEnumerator Aim()
    {
        _agent.isStopped = true;
        _agent.speed = 0;
        _anim.SetFloat("Speed", _agent.speed);
        yield return new WaitForSeconds(1f);
        Shoot();
    }

    void Shoot()
    {
        Debug.Log("Fire!");
        _anim.SetBool("Fire", true);
        if (_nextTimeToFire <= Time.time)
        {
            _nextTimeToFire = Time.time + 1 / fireRate;
            RaycastHit hit;
            if (Physics.Raycast(gunTip.position, gunTip.forward, out hit, Mathf.Infinity))
            {
                PlayerCharacter playerHealth = hit.transform.gameObject.GetComponent<PlayerCharacter>();
                if (playerHealth != null)
                {
                    //Debug.Log("Player is being shot!");
                    playerHealth.Hurt(damage);
                }
            }
        }
    }
}

Hi, @Bezari0us! I changed value in _countdownToShoot to a time, when shoot can be done. Now you dont need to decrease delta time from countdown. Hope it solve your problem.

public class AIBehaviour : MonoBehaviour
{

    public enum State
    {
        FindingTarget,
        Shooting
    }

    public State state = State.FindingTarget;

    public int damage;

    public float moveSpeed;

    public float delayToShoot;

    [Tooltip("The time to check if Player is still there at the position being shot")]
    public float nextTimeToSearch;

    public Transform gunTip;

    private Transform _target;

    private NavMeshAgent _agent;

    private Animator _anim;

    private bool _targetInRange;

    [SerializeField] private float _countdownToSearch;

    [SerializeField] private float _countdownToShoot;

    void Start()
    {
        _agent = GetComponent<NavMeshAgent>();
        _target = PlayerManager.instance.player.transform;
        _anim = GetComponentInChildren<Animator>();
        state = State.FindingTarget;
        _agent.speed = moveSpeed;
        _countdownToSearch = nextTimeToSearch;
        _countdownToShoot = Time.time + delayToShoot;
    }

    private void Update()
    {
        // if there is target to find at all
        if (_target != null)
        {
            // find target
            if (!_targetInRange)
            {
                FindTarget();
            }

            if (state == State.Shooting && _targetInRange)
            {
                // check if player is still at the being shot position
                if (_countdownToSearch <= 0)
                {
                    _countdownToSearch = nextTimeToSearch;
                    RaycastHit hit;
                    if (Physics.Raycast(gunTip.position, gunTip.forward, out hit, Mathf.Infinity))
                    {
                        if (!hit.transform.gameObject.CompareTag("Player"))
                        {
                            Debug.Log("Player has moved!");
                            // then find player again
                            _targetInRange = false;
                            FindTarget();
                        }
                        else return;
                    }
                }
                else _countdownToSearch -= Time.deltaTime;

            }

            else if (state == State.FindingTarget && _targetInRange && state != State.Shooting)
            {
                Shoot();
                _anim.SetBool("Fire", true);
            }
        }
        else
        {
            Debug.LogWarning("Currently there is no player in the scene");
        }
    }

    void FindTarget()
    {
        state = State.FindingTarget;

        _agent.speed = moveSpeed;
        _agent.SetDestination(_target.position);
        _anim.SetFloat("Speed", _agent.speed);
        _anim.SetBool("Fire", false);

        Quaternion lookRotation = Quaternion.LookRotation(_target.position - transform.position);
        transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5f);

        RaycastHit raycasthit;
        if (Physics.Raycast(gunTip.position, gunTip.forward, out raycasthit, Mathf.Infinity))
        {
            if (raycasthit.transform.gameObject.tag == "Player")
            {
                _targetInRange = true;
                Debug.Log("Found Player!");
            }
            else
            {
                _targetInRange = false;
                _agent.isStopped = false;
                return;
            }
        }
    }

    void Shoot()
    {
        state = State.Shooting;
        Debug.Log("Fire!");
        _agent.isStopped = true;

        transform.LookAt(_target);

        if (_countdownToShoot <= Time.time)
        {
            RaycastHit hit;
            if (Physics.Raycast(gunTip.position, gunTip.forward, out hit, Mathf.Infinity))
            {
                PlayerCharacter playerHealth = hit.transform.gameObject.GetComponent<PlayerCharacter>();
                if (playerHealth != null)
                {
                    Debug.Log("Player is being shot!");
                    playerHealth.Hurt(damage);
                }
            }
            _countdownToShoot = Time.time + delayToShoot;
        }
    }
}