- Home /
Component's Start/Awake methods not being called
I have a `GameObject` that has the following structure:
MyObject.cs:
using System;
using UnityEngine;
public class MyObject : MonoBehaviour
{
public TestBase testBase;
}
What I want to do is to be able to change the `testBase` field in using the editor's inspector, using any class that's derived from `TestBase`, like this:
TestBase.cs:
using System;
using UnityEngine;
public abstract class TestBase : MonoBehaviour
{
void Awake()
{
Debug.Log("TestBase.Awake()");
}
}
TestDerived.cs:
using System;
using UnityEngine;
public class TestDerived : TestBase
{
void Start()
{
Debug.Log("TestDerived.Start()");
}
}
Now if I create a `GameObject` that contains the `TestDerived` script and drag it into the corresponding field in `MyObject` in the Unity editor, the field gets initialized properly etc., but neither the base nor the derived class' `Awake()` or `Start()` methods get called when I run the scene.
If instead of using the editor to "populate" the `testBase` field I add an `Awake()` method to `MyObject` and do this:
void Awake()
{
testBase = gameObject.AddComponent<TestDerived>();
}
both `TestBase.Awake()` and `TestDerived.Start()` get called.
What am I missing here? Why aren't the methods called when I add `TestDerived` using the editor, but when I do it in C# everything works as expected?
Answer by Kryptos · Aug 30, 2012 at 11:30 AM
If you want to use derived-class, make the methods in the base class accessible (public or at least protected), and virtual if you plan to override them.
Having a parameter of type TestBase does not mean you actually have such a component (it will be null by default). You need to add the script to the GameObject and drag/drop the reference to your variable in the inspector.
More about virtual methods:
public abstract class TestBase : MonoBehaviour
{
protected virtual void Awake()
{
Debug.Log("TestBase.Awake()");
}
}
public class TestDerived : TestBase
{
protected override void Awake()
{
base.Awake();
Debug.Log("TestDerived.Awake()");
}
void Start()
{
Debug.Log("TestDerived.Start()");
}
}
I know about overriding and virtual methods. If you look at the source code, you'll note that the base class contains Awake() and the derived class contains Start(). Nothing is overridden or hidden.
Regarding your point #2, I wrote this in my question "Now if I create a `GameObject` that contains the `TestDerived` script and drag it into the corresponding field in `$$anonymous$$yObject` in the Unity editor, the field gets initialized properly etc., but neither the base nor the derived class' `Awake()` or `Start()` methods get called." This also means that the field gets initialized properly (i.e. it's not null), but neither Awake() nor Start() gets called.
Awake is hidden in the derived class because it is not visible (public or protected).
Regarding the second point: you said you created a GameObject but you don't tell if the GameObject is actually in the scene.
I used a lot this kind of inheritance and it always worked. So my guess is you forget to mention something you do (or don't do) that causes the whole thing to fail.
Ah, I didn't realize that the GameObject has to be in the scene as well as a component for Awake() and Start() to work. I assumed that merely adding the GameObject as a component would be sufficient.
The problem with adding the GameObject to the scene as well as adding it as a component is that the $$anonymous$$onoBehaviour gets instantiated several times. If I initialize fields in Awake() or Start(), the instance that actually gets its fields initialized is often different from the one that is assigned to the public field of my $$anonymous$$yObject.
I'm still confused what's your problem. Awake and Start is called only at runtime when you start the game, or when your script has an ExecuteInEdit$$anonymous$$ode attribute. But of course only when the script is attached to a gameobject in the scene. Prefabs are just assets which are stored in your project like you have pictures or programs stored on your harddrive. They do nothing until you use them somehow.
Regarding inheritance it's a bit tricky. Usually when a system provides a base class from which you can derive your own classes, the system accesses your instances via a base-class reference. In this case you have to make your methods virtual and override them properly in your derived classes. Unity's $$anonymous$$onoBehaviour class doesn't really work that way. Unity deter$$anonymous$$es for each class which of the Unity callbacks are implemented and calls them accordingly.
That means in a "normal" inheritance scenario when you forget to make it virtual / override it, only the base class method is called. In Unity it's the other way round. Unity only sees the final class. It deter$$anonymous$$es via reflection which methods are implemented and invoke them. So when you "hide" a unity callback in a derived class, Unity will only call the method on the derived class.
As I explained in the question, the problem is that even though the GameObject containing the TestDerived script is attached to a GameObject as a component (but is not added to the scene), the Start() or Awake() methods are never called.
If I use AddComponent everything works fine (i.e. both TestBase.Awake() and TestDerived.Start() gets called), but I'd like to be able to do this in the editor ins$$anonymous$$d of hard-coding it in the script.
Answer by codemaker2015 · Oct 12, 2018 at 09:10 AM
Delete the script and create new one with the same code, attach it to the game object.
Necro-ing comment but this finally solved an hour long bug fixing session for me. What a pain.
Thank you!