How to dynamically construct a reference to a game object by name

Hi - I have game objects tagged MenuOption0, MenuOption1, MenuOption2, etc. I want to keep a currentIndex var, which gets incremented each time the user swipes on the controller. That swipe should increment the currentIndex var, and switch the reference to a new game object, whose text color will be changed.

This is what I’m trying as a test:

GameObject testText = GameObject.Find("MenuOption" + 4);
TextMeshProUGUI thisTextMesh = testText.GetComponent<TextMeshProUGUI>(); 
thisTextMesh.color = colorWhite;

How do I dynamically construct a reference to MenuOption1,2,3,4,etc? Or is there a better way to handle this without writing a big long conditional?

@mheavers
It’s the etc. that makes the setup such an unattractive proposition. When there’s 8, or 20 or more, it gets ugly.

I assume a supervisory script owns the code you posted. I’ll call it a class MenuSupervisor. Something like:

public class MenuItem : MonoBehaviour
{
 void Awake() { MenuSupervisor.RegisterMenuItem( this ); }
}

public class MenuComp : IComparer< MenuItem >
{
 public int Compare( MenuItem a, MenuItem b )
   {
    return System.String.Compare( a.gameObject.name, a.gameObject.name );
   }
}


public class MenuSupervisor : MonoBehaviour
{
 private static List< MenuItem > menuEntries;


 public static void RegisterMenuItem( MenuItem m )
   {
    menuEntries.Add( m );
   }

 void Start()
   {
    menuEntries.Sort( new MenuComp() );     
   }

}

In this approach the objects you call MenuOptionX would need a script attached to each, which is MenuItem in the above example. This script uses Awake (it’s exactly like Start, but all Awakes are completed before the Starts are executed).

MenuItems thus register themselves with the supervisor during the Awake phase (which is before the Start phase).

I assume you want the list in order, so I’ve added an IComparer example to sort the menu items by name, which you could customize for any sorting order you’d prefer.

The supervisor’s Start function, which should be called after all the menu items have registered, sorts the list by name. Take care of your naming convention as MenuOption1 and MenuOption10 would precede MenuOption2 when sorted this way. You may do better with MenuOption01, 02, 03…

In any event, you now have a List which you can address as an array using an index, where each entry is a MenuItem, such that

List[ x ].gameObject.GetComponent<TextMeshProUGUI>().color = colorWhite 

Would work for any x. Well, any x that’s within List.

Of course, the MenuItem could use Start to cache the TextMeshProUGUI if you like.

@mheavers Perhaps I’m not understanding the totality of what you’re trying to accomplish but I feel like the best way you approach this, due to the similar nature of the objects you’re referencing, is with a collection:

MenuOptions collection:

Order the MenuOptions into a container (list, array, etc) on startup. Then whenever your input logic needs to use a new MenuOption, you can just use the reference from your master list. That should let you grab the reference you need by the index at runtime.

Alternatively:

If searching by name is required, and you know the count of MenuOptions, you could similarly use a container and populate it at runtime with a loop. That would eliminate the need to frequently call GameObject.Find();