Raycast detects hit even after you look away (but only down)

Hello, new to Unity, but a generally okay programmer, working in C#.

I’m having an issue when using a raycast to detect an item under a single pixel crosshair set to the centre of the screen (classic FPS setup, mouse controls the camera, and thus this crosshair), to test, I have the system setup so that when you look at an item it turns red and then when you look away from it, it turns blue.

For the most part the system works except when you look down while looking at an item it often stays ‘red’ or looked at, looking away from the item up, left, or right works as expected.

Below is my Crosshair’s Update() function, can anyone see why I’m having this problem? Thank You.

public float interactionDistance = 3f;
private GameObject oldObject = null;

    void Update(){
	RaycastHit hit;
	
	if(Physics.Raycast (Camera.main.transform.position, Camera.main.transform.forward, out hit, interactionDistance)) {
		if(hit.collider.tag == "UsableItem"){
			GameObject objectHit = hit.transform.gameObject;
			if(oldObject == null || oldObject == objectHit){
				objectHit.GetComponent<Renderer>().material.color = Color.red;
			} else if(oldObject != null){
				objectHit.GetComponent<Renderer>().material.color = Color.red;
				oldObject.GetComponent<Renderer>().material.color = Color.blue;
			}
			oldObject = objectHit;
		} 
	}
	else{
		if(oldObject != null){
			oldObject.GetComponent<Renderer>().material.color = Color.blue;
		}
		
		oldObject = null;
	}
}

Based on your code and video it seems like the problem arises because you are looking at the floor which has a collider.

So the cube is selected (red). Then you scroll down and look at the floor.

if(Physics.Raycast (Camera.main.transform.position, Camera.main.transform.forward, out hit, interactionDistance)) {

return true because the ray hits the floor. However the next line

if(hit.collider.tag == "UsableItem"){

return false because the ray has hit the floor and not the cube. In that situation no statements are run. One way to fix this would be combine the if statements so the deselect is done if a nonusable item is hit by the ray, as it would if the ray does not hit anything.

public float interactionDistance = 3f;
private GameObject oldObject = null;
 
void Update(){
    RaycastHit hit;
     
    if(Physics.Raycast (Camera.main.transform.position, Camera.main.transform.forward, out hit, interactionDistance)&&
        hit.collider.tag == "UsableItem") 
    {
        GameObject objectHit = hit.transform.gameObject;
        if(oldObject == null || oldObject == objectHit){
            objectHit.GetComponent<Renderer>().material.color = Color.red;
        } 
        else if(oldObject != null){
            objectHit.GetComponent<Renderer>().material.color = Color.red;
            oldObject.GetComponent<Renderer>().material.color = Color.blue;
        }
        oldObject = objectHit;
    }
    else{
        if(oldObject != null){
            oldObject.GetComponent<Renderer>().material.color = Color.blue;
        }         
        oldObject = null;
    }
}