turning items on & off with Raycast

Hello
I have a script that works
but I feel there is a cleaner way to code

I am shooting a ray at items with tags (“one”, “two”, “three”…)
if hit, these items sets Active other gameObject’s (One, Two, Three…)

The active object should be set back to false when I move off each tag & before I move on to the other :

Here’s my script (working)

public GameObject One;
public GameObject Two;
public GameObject Three;
public GameObject Four;



    private void Update()
     {
 
         RaycastHit hit;
    
         Vector3 forward = transform.TransformDirection(Vector3.forward) * 10;
         Debug.DrawRay(transform.position, forward, Color.green);
        
         if (Physics.Raycast(transform.position, (forward), out hit))
         {
             if (hit.collider.tag == "one")
             {
                 //print("1");
                 One.SetActive(true);
             }
            else
            //Reset if not hitting 
             {
                 //print("Null1");
                 One.SetActive(false);
             }

             if (hit.collider.tag == "two")
             {
                 //print("2");
                 Two.SetActive(true);
             }              
             else 
             {
                // print("Null2");
                 Two.SetActive(false);
             }

             if (hit.collider.tag == "three")
             {
                // print("3");
                 Three.SetActive(true);
             }
            else
             {
                 //print("Null3");
                 Three.SetActive(false);
             }

             if (hit.collider.tag == "four")
             {
                 //print("4");
                 Four.SetActive(true);
             }
             else
             {
                 print("Null4");
                 Four.SetActive(false);
             }
         }

[System.Serializable]
public class Category
{
[SerializeField] private string tag;
[SerializeField] private GameObject label;

    public bool ContainsElement(GameObject candidate)
    {
        return candidate.CompareTag(tag);
    }

    public void ToggleLabel(bool state)
    {
        label?.SetActive(state);
    }
}

// Fill in inspector
// Give the tag (one, two, three, four)
// and the object to toggle on and off
[SerializeField]
private Category[] categories = new Category[4];

private Category lastSelectedCategory;

private void Update()
{
    RaycastHit hit;
    Ray ray = new Ray(transform.position, transform.forward);
    Debug.DrawRay(ray.origin, ray.direction, Color.green);
    Category category;
    if (Physics.Raycast(ray, out hit, 10) && (category = GetCategory(hit.collider.gameObject)) != null)
        SelectCategory(category);
    else
        SelectCategory(null);
}

private Category GetCategory(GameObject gameObject)
{
    foreach(Category category in categories)
    {
        if(category.ContainsElement(gameObject))
            return category;
    }
    return null;
}

private void SelectCategory(Category category)
{
    if(category == lastSelectedCategory) return;

    if(lastSelectedCategory != null)
        lastSelectedCategory.ToggleLabel(false);

    lastSelectedCategory = category;

    if(lastSelectedCategory != null)
        lastSelectedCategory.ToggleLabel(true);
}

Original answer

public string[] TargetTags = new string[]
{
    "one", "two", "three", "four"
};

private GameObject lastHitObject;

private void Update()
{
    RaycastHit hit;
    Ray ray = new Ray(transform.position, transform.forward);
    Debug.DrawRay(ray.origin, ray.direction, Color.green);
    if (Physics.Raycast(ray, out hit, 10) && IsTarget(hit.collider.gameObject))
        SetTarget(hit.collider.gameObject);
    else
        SetTarget(null);
}

private bool IsTarget(GameObject gameObject)
{
    foreach(string tag in TargetTags)
    {
        if(gameObject.CompareTag(tag))
            return true;
    }
    return false;
}

private void SetTarget(GameObject newTarget)
{
    if(newTarget == lastHitObject) return;

    if(lastHitObject != null)
        lastHitObject.SetActive(false);

    lastHitObject = newTarget;

    if(lastHitObject != null)
        lastHitObject.SetActive(true);
}

Thank you ! @Hellium
I love the array!
But the Tagged Objects (one, two…)
dont turn themselves on & off
but other GameObjects that I will choose from the scene & drag into editor

For example, the camera is rotating around the model here, as it passes the Text (with collider & Tag) the raycast hit triggers a new game object where the blue cube is, one the Raycast is not hitting the text collider ( returning null) the game object associated with the specific tag is setActive(false)

Does that make sense?

Thanks so much for your help

~be

@Hellium
Thank you so much! Thats an amazing logic machine.

I’m getting errors though

& in trying to follow the logic…

The first thing I notice I think is that :

line 4 : “[SerializeField] private string Tag;” I think should be lowercase

when I do this it compiles and I get the error :

NullReferenceException: Object reference not set to an instance of an object
raycaster.GetCategory (UnityEngine.GameObject gameObject) (at Assets/_Scripts/raycaster.cs:48)
raycaster.Update () (at Assets/_Scripts/raycaster.cs:38)

Here my line :38 is your above 32
(and my 48, is your 42).

I dont have access to an array in the array in the inspector I can populate with gameObjects, even if I make:
private Category into public Category
to no avail.

Sorry to be such a bother - what you have written is very elegant and I am learning a lot trying to parse it

Thanks!
~be

@Hellium You Sir,
are amazing !
A beautiful script
Thank you so much!
~be