Best practice for finding game objects,Best practice for finding gameobjects

Hi Team,

I have a UI I’m setting up that I want to programmatically change content. See attached picture illustrating the hierarchy of objects.

120556-unityobjectlist.jpeg

I have a script on the BackgroundPanel which searches for individual items, for example, the textbox “heading”, the textbox “LeftTextBox”, and the object “ObjectRight” which may have a video player, a render image, or some other content (currently to be defined, which will be created later).

I currently have the following code to find each item by name - which obviously is totally static. It works, but what I’d like to know is - is there a “best practice” or better way to do this?

public class UIContentController : MonoBehaviour 
{
    Text leftText;
    Text linkBox;

    GameObject objectRight;
    GameObject heading;


	// Use this for initialization
	void Start () {
        heading = transform.Find("Heading").gameObject;
        leftText = transform.Find("LeftTextBox").GetComponent<Text>();
        linkBox = transform.Find("GeniusLink").GetComponent<Text>();

        objectRight = transform.Find("ObjectRight").gameObject;
	}
}

If I use the code

leftText = GetComponentInChildren<Text>();

Then I find the first text component, without finding the correct text component.

Thanks in advance for any assistance.

,Hi Team,

I have a UI I’m setting up that I want to programmatically change content. See attached picture illustrating the hierarchy of objects.

120556-unityobjectlist.jpeg

I have a script on the BackgroundPanel which searches for individual items, for example, the textbox “heading”, the textbox “LeftTextBox”, and the object “ObjectRight” which may have a video player, a render image, or some other content (currently to be defined, which will be created later).

I currently have the following code to find each item by name - which obviously is totally static. It works, but what I’d like to know is - is there a “best practice” or better way to do this?

public class UIContentController : MonoBehaviour 
{
    Text leftText;
    Text linkBox;

    GameObject objectRight;
    GameObject heading;


	// Use this for initialization
	void Start () {
        heading = transform.Find("Heading").gameObject;
        leftText = transform.Find("LeftTextBox").GetComponent<Text>();
        linkBox = transform.Find("GeniusLink").GetComponent<Text>();

        objectRight = transform.Find("ObjectRight").gameObject;
	}
}

If I use the code

leftText = GetComponentInChildren<Text>();

Then I find the first text component, without finding the correct text component.

Thanks in advance for any assistance.

You’ve basically figured out what “Find” does, and that it’s not particularly thrilling.

You’ve also identified what I find all but useless about GetComponentInChildren.

Find also doesn’t descend into children, so you have to manually iterate through a hierarchy when that becomes an issue.

However, not all is lost if you’re looking for something better, which does depend on your use case.

To preface, the assumption I’m making with the suggestion that follows is that UIContentController is a singleton (there’s only 1, and it could be considered a “global” entity, either available to all, or supervisory such that lots of objects look up to it for centralized control).

I’d have the kids call home.

Instead of this parental, supervisory object searching the children for the components, I would consider having the kids do that. For this to work any better, you’d need some quick, simpler means for the kids to find this parent script (UIContentController). It is not practical to assume the order in which start is called among objects, but it seems to me (and this might be documented, but I’ve not read it) that object starts are called from the lowest children upwards. It is likely UIConentController’s start function won’t be called before the children’s start script executes (so you can’t rely upon UIContentController’s start script to initialize the static UICC for them). The script, UIContentController, will exist, however, and can be found.

So, I’d use “lazy initialization” of a global reference to UIContentController. As odd as this may seem, put a:

 static private UIContentController UICC = null;

In your class. This is, basically, a globally accessible value, but it starts out null (you don’t have an instance to one at this point - the very early initialization of the code, and remember I said the assumption is that there will only be 1).

It is private in this example so that only UIContentController can assign it (that keeps it under control).

Next, I’d suggest a static public member function like:

static public UIContentController GetUICC() {...}

The purpose of this function is simply to return UICC, but before doing that check to see if it is ==null. If it is, this is a call from the first child trying to register. In the chilren’s start function, they can:

UIContentController uicc = UIContentController.GetUICC();

Then use the uicc to register themselves (more in a moment).

For the first call made by a child to GetUICC, the static UICC will be null. The function will have to search the hierarchy for the object that owns the UIContentController script component, get the component and set UICC to that (so that all subsequent children will find it much faster).

Since I have no idea where your UIContentController is located, I can’t write a precise example, but it likely starts at the root, checks it’s children (and if you know for certain the owner is at the top level, that might be all that needs to happen). If it is owned by a subobject (child of a top level object), you might already know where that is, so you might be able to tune a “find” command to go right to it.

This approach means a “find” will only have to happen once. Subsequent calls from children will use the cached static UICC.

So, when the “heading” object start function executes, it can call the parent with something like:

UIContentController.GetUICC().SetHeading( transform.gameObject );

The “ObjectRight” can do something similar.

LinkBox might:

UIContentController.GetUICC().SetGeniusLink( GetCompoment<Text>() );

In this way, the kids call home when they start, the parent is only “found” once, and all is a bit faster.

Of course, I’m using member functions in UIContentController as an example method, but you can choose as you prefer (properties, direct manipulation of UIContentController members even though that’s considered naive).

This approach has one significant advantage. If you move the children or rename them, you don’t have to change anything. With the approach you’re using, where UIContentController finds the kids, if, say, GeniusLink were later made the child of a child, you’d have to change UIContentController’s start function to find it in the new location. With this approach, the kid calls home no matter where it goes.