- Home /
Can I call Awake() and OnEnable() separately?
Hello,
I want to instantiate a prefab, and then customize the resulting gameObject before it is enabled in the scene.
What I want to do is :
1. Deactivate the gameObject's prefab
2. Instantiate a copy of the gameObject
3. Call Awake(), to set references, and to call member objects constructors
4. Set specific values on the member objects
5. Enable the gameObject in the scene
Problem is, the first call to gameObject.SetActive(true) calls Awake() again, which reset all the member objects.
So is there a way to enable a gameObject without Awake() being called the first time I do so?
Do I have any control on when Awake() is called ?
Your main fault here is that you call Awake manually. Awake, OnEnabled, Start, Update, ... are callbacks from the engine. You should never call them manually. If you have code that you wish to run manually, create a seperate method for that..
Good point, I would indeed never call update or onenable manually.
How can i accept your comment as the answer ?
Answer by Minuks · Nov 27, 2017 at 02:20 PM
I was thinking to maybe use an Init() method instead of Awake(), but a boolean seems like a more coherent choice. I will do so on my base class :
protected bool AlreadyAwaken = false;
protected virtual void Awake()
{
if (AlreadyAwaken)
return;
else
AlreadyAwaken = true;
// Do stuff
}
Thanks for your advice
Well I don't know how to block the execution of Awake in the child class, so I ended up using an Initialize() method. I don't like it though.
protected bool AlreadyAwaken = false;
public void Awake() // Not virtual = sealed, use initialize ins$$anonymous$$d
{
if (AlreadyAwaken)
return;
else
{
AlreadyAwaken = true;
Initialize();
}
}
// Awake
public virtual void Initialize()
{
}
I remember I have been using something like this:
using System;
using UnityEngine;
namespace Core
{
public class Initializable$$anonymous$$onoBehaviour : $$anonymous$$onoBehaviour
{
public bool IsInitialized { get; private set; }
protected void BaseInitialize()
{
if (IsInitialized) throw new Exception(string.Format("{0}: {1} is tried to be initialized more than once.", GetType().Name, name));
IsInitialized = true;
}
protected void Start()
{
if (!IsInitialized) throw new Exception(string.Format("{0}: {1} is not initialized.", GetType().Name, name));
}
}
}
General idea is that you will need to define your own Initialize in derived class which must call BaseInitialize. And any time when you instantiate object, you will need to call your own initializator, or you'll get error (look at start).
namespace Core.Physics.Gravity
{
public partial class GravityReceiver : Initializable$$anonymous$$onoBehaviour
{
...
public virtual void Initialize(CelestialBody worldBody)
{
BaseInitialize();
ChangeParent(FindParent());
ChangeTrajectory(_parent.CreateTrajectory(WorldToLocalBody(worldBody)));
}
...
}}
So that is something like a pseudo constructor, but I'm not sure that it is a good idea to use something like this. The real solution which is common that is create static method which will create object. If I'm not wrong that is called Factory $$anonymous$$ethod
Well I actually stumbled upon this issue while implementing the Factory design pattern. I think I will use Awake() with normal classes, and Initiliaze() on classes created in the Factory.
Your answer
Follow this Question
Related Questions
Strange Unity state machine behaviour: OnEnable - OnDisable before awake??? 1 Answer
OnEnable, Awake, Start order 8 Answers
physics.OverlapSphere colliders 1 Answer
would Unity disable gameobject temporary and automatically when loading a big assetbundle? 0 Answers
Should OnEnabled() be changed to be called after Start()? 1 Answer