Is there no way to get reference of inactive gameObject?

So I am using GameObject.FindWithTag to get reference of some UI variables,

but I want this process silently be hidden from user's eyesight, so I made gameobject inactive at inspector.

But result null reference error.

So I should make that UI gameobject active, but then I can't work because that UI hinders scene screen.

I thought another way of moving UI gameobject to another position like (2000, 2000, 0) and then make it again to (0, 0, 0)

but this also result in abnormal NGUI scrollview behaviour like after children generated, scrollview's x position set to unintended position like 8000.

So I will blame NGUI and but this project was made from era of there is no UGUI, and still NGUI's scrollview movement has more feature than UGUI's (like drag and drop children moving between scrollviews)

So what can be solution?

1 Like

Easy, but you need to know the parent GameObject.

GameObject obj = parentObject.FindObject("MyObject");

Source: http://answers.unity3d.com/questions/890636/find-an-inactive-game-object.html

2 Likes

There are couple of options to this.

  • Keep object active then disable
  • Disable only renderers if possible

And then you can also use:

transform.Find()
transform.GetComponentsInChildren(true)
Resources.FindObjectsOfTypeAll()

I hope some of this helps.

Thx for all comments,

This seems good except this result in error,

[ this GameObject parent ]

remove ‘this’ is fine?

Can you post example code?

Don't search for the GameObject in the first place. Define a variable in your script, and assign it in the inspector.

2 Likes

As @TonyLi mentions. Is there a reason you need to "find" it instead of creating a reference to it and connecting it in the inspector?

if the Object is disabled. Just use "Resources.FindObjectsOfTypeAll" it finds everything thats loaded, including disabled objects.

var obj= Resources
    .FindObjectsOfTypeAll<GameObject>()
    .FirstOrDefault(g=>g.CompareTag("TagName"));

(you need to be using System.Linq for FirstOrDefault())

Do keep in mind that this way is slow. the best way to handle this if to have a serializableField in your script and manually drag the UI Gameobject to it.

9 Likes

Stop using Find() methods. There is always, guaranteed, literally, every time, a better way.

For example with UI, I've found that organizing things into panels with empty wrappers to hold the managing script is the ideal way to enable/disable child elements (ui graphics) while retaining the ability to communicate on the wrapper/managing script.

Something like this:

+Canvas
++CharacterPanel UI_CharacterDisplay.cs
+++Wrapper
++++CharLvlText
++++CharHPBar
++++CharMPBar

Now, irregardless of whether or not the UI is displayed I can still have UI_CharacterDisplay.cs looking for Action Events, subscribing to stuff, updating the inactive UI, doing whatever I want it to.

If these are very persistent items, such as they always exist in the scene, then just make a static class that houses references to them and anything can simply register itself on the static class, like a Game.cs class with public static UI_CharacterDisplay CharDetails; which literally anything can call at anytime they want without dealing with the stupidity of Find() methods.

This is just one example but you will *find (haha..)*that there is always a better solution than using some kind of Find() method after doing a little bit of strategizing.

3 Likes

example code is in above link.

here it is.

public static GameObject FindObject(this GameObject parent, string name)
{
     Transform[] trs= parent.GetComponentsInChildren(typeof(Transform), true);
     foreach(Transform t in trs){
         if(t.name == name){
              return t.gameObject;
         }
     }
     return null;
}

But so this result in error at [this], [Transform[ ]] part.

Actually I prefer connecting directly to inspector way, but this was part of other developer worked and there is some workload to re-do. (over 10~20 things, of course I can do maybe in 20 minutes, but … human is lazy)

And this way has some advantages that, even if scene is broken and all inspector connecting info was gone, this can preserve because this uses code way.

And also, prefab can’t preserve connecting info to scene’s object, but this can do.

Thx, quite seems good. but slowness is… bad. All gamers hate hiccups at start of the game. (this is because of while getting references in code…at background?)

Thanks for let me know. This seems quite good way, but I can’t understand how to do code exactly. Can you post the code to do this trick?
And yes .Find is very sick and seems stupid.

He means simply make obj a public field and you set it directly in the inspector, this is both the same thing I mentioned and recommend.

public GameObject UiGameObject;

now set the reference in the inspector. No need for Find. and the only thing you have to check is if the reference is null (cause you didn’t set if or the gameobject was destroyed) before you start using it.

Then have them both connect via a ScriptableObject Asset as I mentioned in this thread. This allows all instances of a prefab communicate to all instances of another prefab (in a many-to-many way) and it does so so that prefabs don’t have to reference scene objects.

Never use find. You should make a empty gameobject as a placeholder for its child component. So that the child can be inactive / active. Make the reference with public accessor.

Quality necropost

5 Likes

To anyone who comes across this thread looking for various options on how to handle persistent objects or data: static classes are not only kind of counter to the purpose of object oriented programming, it can introduce bugs that can be very difficult to track down, and could make for exponential use case issues the longer or the more frequent the game is run. I personally think it's a pretty bad trade off for shaving a few milliseconds off when loading a scene. I won't say this is the "wrong" way of handing this, there are certainly instances where global data is extremely useful, but I very strongly disagree with notion that using any set of very simple functions that is an absolutely basic part of Unity is something that should be avoided at all costs in favor of something that is inherently often dangerous with OOP.

Simply adding the objects to script via the inspector is fine for most things, but sometimes, as in the unique cases I have, there may be instances where you will be enabling and disabling persistent objects as various conditions are met in different scenes (as opposed to storing these objects in every single scene and ALSO having to find them each scene with multiple objects, and Unity will obviously not remember these stored references once the objects they are referring to or the objects referring TO them are destroyed, even if they are prefabs), and so far the least buggy and easiest way I've found of doing this is to simply set a single script in each scene that manages triggers for the various objects that will enable and disable them so they can be found by other objects. So far performance on scene loading has not even remotely been an issue, especially since I utilize proper transitions between scenes, and I'm also making a mobile game and testing on older hardware.

Utilizing Start, OnEnable, and OnDisable has allowed me to set up a pretty complex system in almost all of the ways I needed without issue, and it's been very easy to manage.

Just remember of course to never use any Find function in an update method of any kind.

5 Likes

Found this on stack overflow, might be useful to someone:
https://stackoverflow.com/questions/44456133/find-inactive-gameobject-by-name-tag-or-layer?rq=1

Find in-active GameObject by Name:

GameObject FindInActiveObjectByName(string name)
{
    Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
    for (int i = 0; i < objs.Length; i++)
    {
        if (objs[i].hideFlags == HideFlags.None)
        {
            if (objs[i].name == name)
            {
                return objs[i].gameObject;
            }
        }
    }
    return null;
}
2 Likes

Since this is getting necro'd anyway, now you can use UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects(). This returns all root GameObjects, including inactive ones. Then recursively search through them by transform.

Or, as I mentioned a few years ago, assign a reference so you don't have to search for it.

5 Likes