How to make enemy check if it doesn`t see player for certain times it changes state

Hello guys. So I’m making an finite state machine for my enemy behaviors. I’m detecting if player is in sight of enemy by raycasting using this block of code:

      public bool TargetInSight()
    {

        if (TargetInRange())
        {
            Vector3 dir = player.transform.position - transform.position;
            float angle = Vector3.Angle(dir, transform.forward);
            RaycastHit hit;

            if (angle < enemyFov / 2)
            {
                for (int i = 0; i < angle; i++)
                {
                    if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 1, transform.position.z),
                    transform.forward + new Vector3(i - angle / 2, 0, 0), out hit, enemyViewDistance, NotEnemy))
                    {

                        if (hit.collider.tag == "Player")
                        {
                            Debug.Log("true");
                            return true;
                        }

                    }

                }
            }
        }

        return false;

    }

TargetInRange is just a simple Vector3.Distance.

when I detect the player I change the state to attack, so the problem is in attack state I can not use the same function bc it returns false some frames and it causes the enemy to switch to the next state for a short period of time

its like attack, attack, then move ahead, attack, move move attack etc. What I wanna do is to check if player is not detected for some time like 2f, only then change the state. But I can not do it. I tried checking with Time.time but couldn’t get it to work.

any help is appreciated. Thanks

You could make a coroutine.

IEnumertor WaitForValidAttack()
{
    float timer = 0.0f
    
    waitingForValidAttack = true;

    while( timer < 2.0f  )
    {
        timer += Time.deltaTime;
        yield return null;
    }
    if( TargetInSight() )
    {
        //Attack
    }
    waitingForValidAttack = false;
}



private waitingForValidAttack = false;   

public bool TargetInSight()
         {
             if (TargetInRange())
             {
                 Vector3 dir = player.transform.position - transform.position;
                 float angle = Vector3.Angle(dir, transform.forward);
                 RaycastHit hit;
                 if (angle < enemyFov / 2)
                 {
                     for (int i = 0; i < angle; i++)
                     {
                         if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 1, transform.position.z),
                         transform.forward + new Vector3(i - angle / 2, 0, 0), out hit, enemyViewDistance, NotEnemy))
                         {
                             if (hit.collider.tag == "Player")
                             {
                                 Debug.Log("true");
                                 if(!waitingForValidAttack)
                                     StartCoroutine( WaitForValidAttack() );
    
                                 return true;
                             }
                         }
                     }
                 }
             }
             return false;
         }

So while waitingForValidAttack is true, you don’t need to call TargetInSight from anywhere else until the coroutine is finished and waitingForValidAttack gets set back to false.