There are two ways I would do it. Pseudo below:
#Countdown Approach
You will have this running easier with a simple countdown on the object. Player looks at object, object counts to 3, object confirms player is still looking at object. Your only issue here is that if the player looks away, and just happens to be looking back at the end of that 3 seconds, your going to receive a false positive.
Player
Update()
{
if(raycast(eyePosition, eyes.forward, out ray))
{
if(out.tag == "object")
{
object.SendMessage("ICanSeeYou");
}
}
}
Objects
IEnumerator ICanSeeYou()
{
yield return new WaitForSeconds(3.0f);
if(raycast(playerEyePosition, playerEyes.forward))
{
// player is looking at the object
}
}
#Constant Tick Approach
In this method, the player confirms it is looking at the object every update. Then, at every late update (guaranteed to run after the update cycles), the object confirms it is being looked at and increments its counter. This way, the object confirms it is being looked at for 3 seconds. That said, the object is not only constantly checking and having to account for more variables, but ever object will have to process at each late update. This is going to be more reliable in ensuring the rules of the game remain intact, but will be less efficient, the more objects you have in your scene.
Player
Update()
{
if(raycast(eyePosition, eyes.forward, out ray))
{
if(out.tag == "object")
{
object.SendMessage("ICanSeeYou");
}
}
}
Objects
bool spied = false; // is the object being looked at this frame?
float spyTime = 0; // how long has the object been looked at for?
float spyStart; // what time did we start looking at the object?
void LateUpdate()
{
if(spied)
{
if(spied == 0.0f)
{
spyTime = time.time - spyStart;
}
else
{
spyTime += time.deltaTime;
if(spyTime >= 3.0f)
{
// object has been looked at for 3 straight seconds
}
}
else
{
spied;
spyTime = 0.0f;
spyStart = 0.0f;
}
spied = false;
}
void ICanSeeYou()
{
spied = true;
if(spyTime == 0.0f)
{
spyStart = time.Time;
}
}
I have listed the LateUpdate function for the object. This works just like Update, but guarantees all Update functions have been processed. This guarantees we will always check the players sight, then the object. I would also only recommend using the spyStart variable if you want to be pedantic in measuring the three seconds. Time delta is going to be able to handle the measurement as accurately as possible, apart from the first frame. Since the player is going to trigger the object between update functions, and time delta measures the time between the current and last update, the first time increment is going to overshoot itself by a small amount.