Search Unity

How do I use GameObject.Find("") to find an inactive object.

Discussion in 'Scripting' started by steadmuffin, Aug 28, 2016.

Thread Status:
Not open for further replies.
  1. steadmuffin

    steadmuffin

    Joined:
    Jun 1, 2016
    Posts:
    49
    I noticed that GameObject.Find cannot find an object that is set inactive. Is there another method I could use?
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    Nope. Not really another way directly.
    You could have an active parent that is an empty gameobject and find that gameobject, then use FindChild or GetChild.
    Or you could find an object that has a varaible reference to the gameobject you really want to find, but otherwise, you can't find inactive objects with GameObject.Find.
     
  3. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    If you're in need of finding disabled objects directly, or any objects really without a direct interaction like a collision, you should have some sort of manager for those object types (a singleton possibly) that you can reference and just have the manager deal with it.

    GameObject.Find, FindGameObjectsWithTag, and other functions that search the entire scene are very slow and I've only ever used them when quickly prototyping an idea. If every GameObject of a given type registers themselves to a list within a manager script, then removes themselves when they die (or even just letting the manager handle those things itself), then you'll find things far easier to deal with later.
     
    passerbycmc and Kiwasi like this.
  4. ritesh_khokhani

    ritesh_khokhani

    Joined:
    Jun 26, 2013
    Posts:
    47
    Object pooling is the best suitable solution for you!
     
  5. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    Object pooling is designed for reusing objects over and over. Generally if you have say, 20 bullet objects. You fire a few, then return them back to the "pool" to use again without destroying or having to instantiate new ones. If OP is trying to find a single object, object pooling would serve no purpose.
     
    Jaxcap, mark_cb and DonLoquacious like this.
  6. DroidifyDevs

    DroidifyDevs

    Joined:
    Jun 24, 2015
    Posts:
    1,724
    Once an object is inactive, you can't find it. However you shouldn't be using GameObject.Find at all as it is very slow. I ONLY use it in the Start function. Why do you need to find an inactive object? Why are you even de-activating it in the first place?
     
  7. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,089
    There is a nasty way of doing it within the editor - it's handy for running custom editor tools (e.g. I used this in the past for building sprite atlases in EZGUI).

    Code (CSharp):
    1.     Transform[] GetAllDisabledSceneObjects()
    2.     {
    3.         var allTransforms = Resources.FindObjectsOfTypeAll(typeof(Transform));
    4.         var previousSelection = Selection.objects;
    5.         Selection.objects = allTransforms.Cast<Transform>()
    6.             .Where(x => x != null )
    7.             .Select(x => x.gameObject)
    8.             .Where(x => x != null && !x.activeInHierarchy)
    9.             .Cast<UnityEngine.Object>().ToArray();
    10.        
    11.         var selectedTransforms = Selection.GetTransforms( SelectionMode.Editable | SelectionMode.ExcludePrefab);
    12.         Selection.objects = previousSelection;
    13.      
    14.         return selectedTransforms;
    15.     }  
    16.  
     
  8. pavlito

    pavlito

    Joined:
    Nov 27, 2007
    Posts:
    136
    Assuming you place your inactive object inside a parent, then you can place a script on the parent with something like

    Code (CSharp):
    1. transform.GetComponentInChildren<YourType>(true); // returns first child with component (inactive included)
    2. transform.GetComponentsInChildren<YourType>(true); // returns array of all children that have the component (inactive included).
    this code assumes that your children objects have a 'YourType' component (script) attached to them.
    Note, if your parent object has the same component (in this case YourType), GetComponentsInChildren<YourType>() will return the parent as well.
     
    Last edited: Aug 29, 2016
    eliteforcevn likes this.
  9. mj321

    mj321

    Joined:
    Aug 23, 2016
    Posts:
    21
    There is a way to find inactive gameobjects in a scene.

    First get a list of root objects for the scene:
    Code (CSharp):
    1. Scene scene = SceneManager.GetActiveScene();
    2. var game_objects = new List<GameObject>();
    3. scene.GetRootGameObjects(game_objects);
    4.  
    From there you can recursively iterate over the children of all GameObjects in the list.
     
  10. Zarezy

    Zarezy

    Joined:
    Mar 11, 2014
    Posts:
    12
    Here is a generic method that searches through all hierarchy for the first active/inactive object of Type:

    Code (CSharp):
    1. public static T FindObjectOfTypeEvenIfInactive<T>() where T : MonoBehaviour
    2. {
    3.    return Resources.FindObjectsOfTypeAll<Transform>()
    4.       .Select(t => t.GetComponent<T>())
    5.       .FirstOrDefault(c => c != null);
    6. }
    Example:
    Code (CSharp):
    1. var mouseDummyController = FindObjectOfTypeEvenIfInactive<MouseDummyController>();
     
  11. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    But this is the Unity Forums. Any of the following are allowed for any Q:

    o Use an object pool

    o Use Design Patterns. Remember singletons should be used [always] / [never].

    o Rewrite your code to cache everything (which would solve the problem here, which means you must give non-helpful examples of component caching.)

    o Use the LINQ library. Also insist Unity update to the most recently proposed version of C# and .NET.
     
    Reahreic, neonblitzer and Arsonistic like this.
  12. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    In case someone comes across this page via an internet search for this common problem: the above answers ignore one specific case in which it is possible to use Find() to get an inactive object if (and only if) you give Find() the full path to a specific gameobject so it doesn't need to do an actual search (e.g. "MyStuff/TheseGuys/ThisSpecificGuy" rather than just "ThisSpecificGuy") I've found this through trial and error. Note that this only works if the object doesn't have any child objects, since then it tries to search the child objects. But if the inactive object is at the bottom of a path with no child objects underneath, then it'll return that object even if it's inactive.
     
  13. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    Hmmm..."can't have child objects" is a serious limitation (and it feels a little like a bug). Plus, if you already know the parent and the path, it's easier to use transform.Find, as in: animalParent.Find("cow"). That's what the second reply from Brathnann suggests. It works on inactive objects (both are named "Find", but they are 2 completely different functions).
     
  14. idbrii

    idbrii

    Joined:
    Aug 18, 2014
    Posts:
    51
    Using the path functionality of GameObject.Find is useful for editor code where storing references isn't possible (storing paths in EditorPrefs.SetString to bookmark objects between editor sessions), so I ran into this problem but none of the above approaches work well for my use case.

    (Looks like they fixed the inconsistency HonoraryBob mentioned -- now GameObject.Find never returns inactive objects.)

    With a few helper functions, here's my FindObjectWithScenePath. Unlike GameObject.Find, it only accepts a scene path. It needs work to support multiple scenes.
    Code (CSharp):
    1. using System.Linq;
    2. using UnityEngine.SceneManagement;
    3. ...
    4. //
    5. // Good for editor code, but not suitable for runtime.
    6. //
    7.  
    8. public static GameObject FindRootObjectWithName(string name) {
    9.     return SceneManager.GetActiveScene()
    10.         .GetRootGameObjects()
    11.         .Where(obj => obj.name == name)
    12.         .FirstOrDefault();
    13. }
    14. // Searches children, not descendants.
    15. public static Transform FindChildWithName(Transform parent, string query) {
    16.     for (int i = 0; i < parent.transform.childCount; ++i) {
    17.         var t = parent.transform.GetChild(i);
    18.         if (t.name == query) {
    19.             return t;
    20.         }
    21.     }
    22.     return null;
    23. }
    24. // Like GameObject.Find when using paths, but includes inactive.
    25. // Example: FindObjectWithScenePath("/Geometry/building01/floor02")
    26. public static GameObject FindObjectWithScenePath(string path) {
    27.     Debug.Assert(!string.IsNullOrWhiteSpace(path), "Must pass valid name");
    28.     Debug.Assert(path[0] == '/', "Must pass scene path (starting with /)");
    29.     path = path.Substring(1);
    30.     var names = path.Split('/');
    31.     if (names.Length == 0) {
    32.         Debug.Assert(false, "Path is invalid");
    33.         return null;
    34.     }
    35.     var go = FindRootObjectWithName(names[0]);
    36.     if (go == null) {
    37.         return null;
    38.     }
    39.     var current = go.transform;
    40.     foreach (var query in names.Skip(1)) {
    41.         current = FindChildWithName(current, query);
    42.         if (current == null) {
    43.             return null;
    44.         }
    45.     }
    46.     return current.gameObject;
    47. }
    48.  
     
  15. VeteranXT

    VeteranXT

    Joined:
    Jul 9, 2021
    Posts:
    9
    Code (CSharp):
    1.  public T GetComponentType<T>(string name, string parent) where T : Component
    2.     {
    3.         T[] col = GameObject.Find(parent).GetComponentsInChildren<T>(true);
    4.         foreach (var item in col)
    5.         {
    6.             if (item.name == name)
    7.             {
    8.                 return item;
    9.             }
    10.         }
    11.         return null;
    12.     }
     
  16. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Remember the first rule of GameObject.Find():

    Do not use GameObject.Find();

    More information: https://starmanta.gitbooks.io/unitytipsredux/content/first-question.html

    More information: https://forum.unity.com/threads/why-cant-i-find-the-other-objects.1360192/#post-8581066

    In general, DO NOT use Find-like or GetComponent/AddComponent-like methods unless there truly is no other way, eg, dynamic runtime discovery of arbitrary objects. These mechanisms are for extremely-advanced use ONLY.

    If something is built into your scene or prefab, make a script and drag the reference(s) in. That will let you experience the highest rate of The Unity Way(tm) success of accessing things in your game.


    Keep in mind that using GetComponent<T>() and its kin (in Children, in Parent, plural, etc) to try and tease out Components at runtime is definitely deep into super-duper-uber-crazy-Ninja advanced stuff.

    This sort of coding is to be avoided at all costs unless you know exactly what you are doing.

    Botched attempts at using Get- and Find- are responsible for more crashes than useful code, IMNSHO.

    If you run into an issue with any of these calls, start with the documentation to understand why.

    There is a clear set of extremely-well-defined conditions required for each of these calls to work, as well as definitions of what will and will not be returned.

    In the case of collections of Components, the order will NEVER be guaranteed, even if you happen to notice it is always in a particular order on your machine.

    It is ALWAYS better to go The Unity Way(tm) and make dedicated public fields and drag in the references you want.
     
  17. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,443
    @VeteranXT , please don't necro a long-dead post like this.
     
Thread Status:
Not open for further replies.