- Home /
When is Awake called on an inactive gameobject
Hi,
I want to be able to configure the properties of a prefab instance (which is created at runtime), prior to its Awake calls (I am using Unity 4.2 btw). My first thought was to deactivate the prefab before instantiating it and this seems to work fine. However, the documentation states
Awake: This function is always called before any Start functions and also just after a prefab is instantiated. (If a GameObject is in-active during start up Awake is not called until it is made active, or a function in any script attached to it is called.)
The bold part is what concerns me. While testing this, calling a function or setting a property on a script did not cause Awake to be called.
So, in which cases is Awake called on an inactive gameobject ? Am I interpreting the documentation wrong ? Is the documentation wrong ? Is there a bug in Unity 4.2 ?
Edit: Note that the part of the documentation that this was taken from describes what happens during a scene load (couldn't find this type of information for runtime instantiation). So it might be that inactive gameobjects are treated differently during during scene load and later. However, I want to be sure so that I don't build a solution which will break in later versions of Unity.
Any help would be appreciated.
Thanks,
Ben
It might also be possible to move the prefab's Awake into Start. That's called a lot later, giving you time to mess around.
Or if you are always going to spawn then set a few values, could have no Awake/Start, and use a public init
function, with inputs from the spawner.
This is not really an option for me, because the solution has to work for all possible components.
To give you a little insight in what I am building: the software allows a non-programmer to define an "object type" which has multiple "attributes".
The user configures this "object type" once by specifying the prefab(s) to use and by specifying "configuration actions". An example of the latter is the binding of an attribute to a certain component's property.
By configuring the object before Awake, it is just the same as if a user had manually constructed and configured the object. Because of this, no existing code has to be modified and all existing components (even the ones I do not have the source of) can be used. So I really prefer to have a generic way to do it pre Awake, because it is much less work and much less error prone.
Ah...so 3rd party prefabs might come with an existing Awake, and the authors might not be comfortable making certain code changes.
I've found that "works with anything" systems sometimes turn into "O$$anonymous$$, not anything." If you need, people often don't $$anonymous$$d a set of simple requirements. Gives them a feeling that they made and learned something.
Answer by cmdeviant · Oct 25, 2013 at 09:46 AM
Let's make a small experiment.
Create empty scene and add two game objects to it with names "ObjectA" and "ObjectB". Then add appropriate scripts to them with the same names.
ObjectA.cs:
public class ObjectA : MonoBehaviour {
public GameObject objectB;
void Start () {
objectB.GetComponent<ObjectB>().Test();
//objectB.GetComponent<ObjectB>().ForceActivation();
}
}
ObjectB.cs:
public class ObjectB : MonoBehaviour {
void Awake () {
Debug.Log("Awake");
}
void Start () {
Debug.Log("Start");
}
void OnEnable() {
Debug.Log("OnEnable");
}
void OnDisable() {
Debug.Log("OnDisable");
}
public void Test() {
Debug.Log("Test");
}
public void ForceActivation() {
this.gameObject.SetActive(true);
Debug.Log("ForceActivation");
}
}
Uncheck active mark of ObjectB on scene. And than drag this object in to the "Object B" field inside ObjectA component in your Unity Editor's Inspector view.
Run scene. ObjectB remains inactive. And you will see output in the console:
Test
ObjectB is still inactive and will be remain so. Now activate ObjectB in the Inspector View and you'll see in console:
Awake
OnEnable
Start
Next change Start() function in ObjectA.cs
to this:
void Start () {
//objectB.GetComponent<ObjectB>().Test();
objectB.GetComponent<ObjectB>().ForceActivation();
}
Run scene again. ObjectB will be activated and console output will be:
Awake
OnEnable
ForceAcivation
Start
Thanks for your answer. So the question remains, what does the bold part in the documentation mean and can we rely on the demonstrated behaviour in future releases.
Ben, I think you can rely on this behaviour. I don't remember they change anything since version 2.7 of Unity.
I think I will do that. It makes my system so much cleaner and it saves me a lot of work. Thanks for your input.
Answer by RDeluxe · Nov 05, 2014 at 06:24 PM
This bold part is actually not clear, and here is a clarification : http://forum.unity3d.com/threads/unityevent-disabled-objects-awake-failure.267241/
As Tim C says in this thread : "If a GameObject is inactive during start up Awake is not called until it is made active, or an Unity lifetime function in any script attached to it is called. (OnEnable, OnCollisionEnter)"
That means that calling normal functions is not going to "awake" your script.
Answer by mathieso · Oct 06, 2021 at 03:06 PM
Something that seems to work for me. Useful when I have GameObjects that are inactive when the game starts, but I still want to be able to call methods scripts attached to those GameObjects.
Create a new abstract class:
/// <summary>
/// Helps with the problem that Awake() and Start() don't run on inactive GameObjects, when a method of the objects
/// is called.
/// </summary>
public abstract class UIModalStarter : MonoBehaviour
{
protected bool hasWokenUp = false;
protected abstract void Awake();
protected abstract void Start();
protected void WakeUp()
{
if (!hasWokenUp)
{
Start();
Awake();
hasWokenUp = true;
}
}
}
Derive from this, instead of MonoBehavior. In public methods (that you want to call when the GameObject the script is attached to is inactive), call WakeUp(). In Start() and Awake(), test to make sure that the flag has not been set.
public class ScriptAttachedToInactiveGameObject: UIModalStarter
{
...
protected override void Awake()
{
if (hasWokenUp)
{
return;
}
...
}
protected override void Start()
{
if (hasWokenUp)
{
return;
}
...
}
public void DoSomething() {
WakeUp();
...
}
}
Not elegant, but it seems to work, and I understand it.
Your answer
Follow this Question
Related Questions
Instantiate a prefab and initialise some of its properties? 1 Answer
Instantiating in Awake() v Setting up prefab instances in Editor performance difference? 1 Answer
Instantiate individual components of a prefab? 1 Answer
Issue Instantiating prefab in C# 0 Answers
How do I make a clone of a prefab appear on the correct layer? [5.2.2f1] 1 Answer