Search Unity

Question Is a parent object guaranteed to available to its child object?

Discussion in 'Scripting' started by pyjamaslug, Mar 29, 2023.

  1. pyjamaslug

    pyjamaslug

    Joined:
    Jul 5, 2017
    Posts:
    51
    In my system, I am using a script located on a gameobject located somewhere down in the heirarchy to find the unique ID of an object at a higher point in the heirarchy. This doesn't have to be the root object, just somewhere higher than the searching object.

    In start(), I recurse up the heirarchy looking for a specific script attached to an object using GetComponent() and the first one I find, I get the ID of the transform it is attached to.

    I want to think that parent objects are available in this way to any child object. Am I right?
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    If an object is actually a child of another object, yes of course you can always access it.

    Are you aware of this by the way?
    https://docs.unity3d.com/ScriptReference/Component.GetComponentInParent.html
    This will handle the "searching up the tree" for you.
     
    Bunny83 and Kurt-Dekker like this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,740
    If a Transform.parent is non-null, the only thing that guarantees is that there is at least ONE Transform immediately above the object in question.

    As to what Components are on it, that's not guaranteed in any way.

    You can crawl up yourself, or perhaps consider using either:

    GetComponentInParent<T>()


    or

    GetComponentsInParent<T>()
     
    pyjamaslug likes this.
  4. pyjamaslug

    pyjamaslug

    Joined:
    Jul 5, 2017
    Posts:
    51
    Is this true even for scripts started on child objects? It doesn't seem reasonable that a child object can be instantiated before its parent, or even that a parent object will be partially instantiated before moving on to a child. I know that the manual states exactly what you have said but still...

    By the way I can't use
    GetComponentInParent<T>()

    as that returns only a reference to the component and I want a reference to the object.
     
  5. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,443
    Once you have a reference to a component, then
    thatComponentReference.gameObject
    is the GameObject that has that component.

    When a component script gets its Awake, you should not depend on any other object existing except its parent, or any other components except components on the same object. It's really for you to set up things inside your own component state. OnEnable is your first call where you can depend on everything around you being in the right state for deep initialization such as dependency injection or component searches outside this object.

    I'd have to do a test to be 100% sure, but I am already 98% sure that by the time your component gets OnEnable, you can depend on ALL of the children objects that were co-serialized (by scene or prefab instantiation) already existing and their active and enabled components already having had their Awake, and all of the parent objects existing and their enabled components already having had their Awake AND OnEnable.
     
    Last edited: Mar 29, 2023
    Bunny83 likes this.
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    All of the objects in the whole prefab hierarchy will exist by the time any of your code can run, don't worry about it.

    You can still use it just fine. Every component has a
    .gameObject
    property if you really need a reference to the GameObject.

    Code (CSharp):
    1. MyScript ms = GetComponentInParent<MyScript>();
    2. GameObject theObject = ms.gameObject;
     
    Last edited: Mar 30, 2023
    pyjamaslug and Bunny83 like this.
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,000
    Exactly. When a prefab is instantiated, the whole object is cloned / deserialized before the first Awake is called on that object. The same should be true for scenes that load. Of course the order in which Awake methods may be called depends on many factors. So getting a reference to another object or component should be no problem, but don't assume the object has initialized itself already. Serialized values should be available immediately
     
    pyjamaslug and PraetorBlue like this.
  8. pyjamaslug

    pyjamaslug

    Joined:
    Jul 5, 2017
    Posts:
    51
    Thanks, all. That confirms what I had assumed/hoped (it isn't the sort of thing you can comprehensively test for). I am working out of Start() and I only need objects to be there, active or not, and all their components to be present.
    And thanks for the heads up about .gameObject on the component - it'll get rid of at least two lines of code!
     
  9. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,740
    You can actually get rid of ALL the code if you can simply drag the references in, aka "Do it the Unity Way(tm)."

    Randomly ransacking the scene hierarchy looking for stuff should always be an absolute last resort.

    Otherwise if you're doing procgen or late-lazy-loading type stuff, then an explicit service locator pattern is definitely better than any form of GetComponent<T>() calls.

    And of course...

    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
     
    Ryiah and Bunny83 like this.