- Home /
GetComponentInChildren returns null during Awake()
I'm having some trouble trying to maintain a referenceto my Controller class from each of my other classes. I'm trying to maintain this reference by calling GetComponentInParent
during the Awake
method, however this returns null. If I call it during the Start
method, it returns as would be expected.
Say I have two objects in my Scene:
Controller (parent)
Player (child)
public class Controller : MonoBehaviour
{
private Player _player;
private void Awake()
{
// Gets the object as expected
_player = GetComponentInChildren<Player>();
}
}
public class Player : MonoBehaviour
{
private Controller _controller;
private void Awake()
{
// fails to get the object, returns null
_controller = GetComponentInParent<Controller>();
}
private void Start()
{
// gets the object
if (_controller == null)
_controller = GetComponentInParent<Controller>();
}
}
During the Player.Awake()
call, the Controller
component cannot be found, and returns null. However, in the Player.Start()
call, it's found.
I really want to link up my dependencies during the Awake
function for all classes - how can I achieve this?
Thanks!
Note: My script execution order dictates that the Controller script will run before the Player script, and this is visually confirmed while the debugger is attached to Unity.
The way Unity starts up, it is not really a good idea to do that. Use Awake for internal initialization and Start for anything that has to do with other objects
Agree with the other comments. This seems a strange way of doing things. Your controller only controls things that are its direct children? If the objects are set up in the scene when you load it, you can connect them in the inspector. If they're instantiated in code, connect them after instantiating them.
But also, this looks like a one-to-one relationship. If so, why do you need to find it twice...?
public class Controller : $$anonymous$$onoBehaviour
{
private Player _player;
private void Awake()
{
// Gets the object as expected
_player = GetComponentInChildren<Player>();
_player.controller = this;
}
}
I really want to link up my dependencies during the Awake function for all classes
$$anonymous$$aybe if you could explain what makes you think you want to do that, it'll be easier for people to explain why you actually don't.
Thanks for your comments, guys. Can you please help me understand what is meant by 'internal initialization'? The way I see it, my Player object depends on a reference to the Conrtoller object (and vis versa), so they should each get this during the Awake function. I guess I'm wrong, but I dont understand how.
@Bonefire-boy, your suggestion would probably work great for this limited example, however I have many other classes that need to get a refrence to other classes - this would not be suitable for all.
I think what I'm trying to achieve is pretty basic; what would be the standardised way of achieving this?
Thanks
Internal initialization in Awake meaning things only to that object, like grabbing components attached to the object itself. If you need initialization with other objects (such as child or parent objects) it should be done in Start.
@Ymrasu, thanks that deffo helps! I guess I'm trying to treat the Awake function like a standard constructor, and thats really not what it is.
Anyways, gathering these dependencies during the Start method seems to give me a what I need, so I think thats the answer.
I've read other suggestions elsewhere (using singletons, using DI frameworks) which sound like they come with their own downside's. Simply getting the objects in the Start method seems to give me what I want.
Thanks all!
Answer by AbubakrKhan · Feb 07, 2019 at 01:13 AM
I have done this for you. Different methods to access script of parent object from child object vice versa. [Use of GetComponentsInChildren() and GetComponentInParent()]
3 Scripts each holding a method that I am accessing : GrandParent , Parent, Child attached to 3 Objects
GrandParentObject
--------------------------- ParentObject
------------------------------------------------- ParentObject
This Script Shows multiple methods of doing the same thing for better understanding. There is another way of doing it by just making a public static instance of a class and then u can use that instance directly in other class without needing to create an object of that class. I can go in detail of this one in comments if required. Thanks if it answers what you are looking for please mark it as answered. Cheers!
GrandParent Class
using UnityEngine;
public class GrandParent : MonoBehaviour {
//Method 1: Accessing Child Script From GrandParent Script
GameObject parentObject;
GameObject childObject;
Child child;
Parent parent;
//Method 2: Accessing Child Script From GrandParent Scrip
public Transform[] childrenObjects;
void Awake () {
print("---------------- METHOD 1 -------------");
parentObject = transform.Find("Parent").gameObject;
childObject = transform.Find("Parent/Child").gameObject;
parent = parentObject.GetComponent<Parent>();
child = childObject.GetComponent<Child>();
child.InChild();
parent.InParent();
print(" --------- Method 1 short to access child -------------");
child = this.transform.Find("Parent/Child").gameObject.GetComponent<Child>();
child.InChild();
//METHOD 2
print("----- Method 2 GetComponentsInChildren When you have Alot of childrens -----");
childrenObjects = GetComponentsInChildren<Transform>();
for(int i = 0; i < childrenObjects.Length; i++)
{
if (childrenObjects[i].name == "Child")
{
child = childrenObjects[i].GetComponent<Child>();
child.InChild();
}
if (childrenObjects[i].name == "Parent")
{
parent = childrenObjects[i].GetComponent<Parent>();
parent.InParent();
}
}
print("----- METHOD 2 With FOREACH Loop ----");
foreach(Transform children in childrenObjects)
{
if(children.Find("Child")){
child = children.GetComponentInChildren<Child>();
child.InChild();
}
if(children.Find("Parent")){
parent = children.GetComponentInChildren<Parent>();
parent.InParent();
}
}
}
public void InGrandParent()
{
print("InGrandParent Object");
}
}
Child Class
using UnityEngine;
public class Child : MonoBehaviour {
Transform GrandParentObject;
GrandParent gp;
Parent p;
public void Start()
{
print("--------- METHOD 1: From Child T GRAND PARENT ---------");
GrandParentObject = transform.root;
gp = GrandParentObject.GetComponent<GrandParent>();
gp.InGrandParent();
print("-----------METHOD 2: From Child to Parents ----------------");
gp = GetComponentInParent<GrandParent>();
gp.InGrandParent();
p = GetComponentInParent<Parent>();
p.InParent();
}
public void InChild()
{
Debug.Log("child component found");
}
}