- Home /
What happens to the code of the Start/Awake function when I deactivate a gameobject?
To populate a dungeon, I instantiate the enemies, initialize them through an interface and then deactivate them until the player enters the room where those enemies are positioned.
If I deactivate an enemy before the Start() function or the interface function, or even the Awake() function of an enemy are done, what happens to the code when I reactivate the enemy?
Does Unity let those functions end their code and only then, it deactivate the scripts? Or does it interrupt them and resume them when the gameObject is activated again? Or does it interrupt them and never resume them since they run only once per life time?
Thanks.
Answer by Bunny83 · Oct 15, 2015 at 12:16 PM
In Unity nothing can be interrupted (with the exception of coroutine but they aren't methods in the first place) as everything (scripting related) runs in a single thread. So no matter what method is currently running it can't be "interrupted" by another from "outside".
If i got you right you have a prefab which you instantiate (with Instantiate) at runtime. The behaviour of Awake and Start depends on the active / enabled state of your prefab. If the script is enabled and the gameobject is active in the prefab, this would happen:
// C#
GameObject inst = (GameObject)Instantiate(prefab);
inst.SetActive(false);
When call Instantiate and (as said above) the script and gameobject is enabled / active, Awake will be called immediately. Actually Awake will be called inside Instantiate. So when Instantiate returns Awake has already been called and finished.
Start on the other hand will always be called at the beginning of the next frame. So if you immediately disable the gameobject Start won't be called until you reenable it.
However if the prefab is already disabled, even Awake won't be called until you enable it. Even here Awake will be called immediately when you enable the instance. Keep in mind that ".enabled" is not a variable but a property. So when assigning "true" to that property you actually call the set method. Awake will be called from inside the set method. So Awake will have finished execution when the set method of the property returns.
Start always behaves the same. It's always called at the beginning of the next frame.
Also, as you can read in the docs, Awake as well as Start will only be called once in the lifetime of the object. So if both got already called nothing will happen if you disable / enable them again.
If you need Start() to run each time, you can use this:
void OnEnable()
{
Start();
}
No, simply, no ^^. You should never (ever) do this.
OnEnable is also called when the object is enabled for the first time, so just put your code in OnEnable. Start is ment to only run once. Calling it manually is a no-go. If you ever work in a larger $$anonymous$$m and you do something like this, you might want to hide somewhere before they get you ^^.
Got a good reason for this?
This code has been used extensively by many people :D
Edit : NV$$anonymous$$ I get what you are saying.
It shouldnt be that hard to prevent it running twice. Simply set a flag in Start and use that condition in the OnEnable.
That fact that you can invoke Start() manually spells out that there are situations where you might need to, and I've seen it a fair few times.
And really, Coroutines aren't an exception to that rule either. They aren't really being interrupted, but told to stop when you use yield. A subtle but important difference.
Well, "told to stop" also doesn't sound right ^^. A coroutine is not a method. That's why it's hard to compare with a normal method. It's a class instance which represents a statemachine. Yes, each "state" in the created statemachine can't be interrupted either. It will always run through the whole state. "yield" just indicates a "state switch" / transition.
However if you "see" a coroutine like a method (which most people do) the execution can be interrupted or even aborted. Only at yield statements but that wasn't the point. If you make Start a coroutine it's possible that it doesn't complete because the object might have beed destroyed,
A coroutine doesn't run on it's own it has to be "actively" continued. That part is done by Unity's coroutine scheduler. When you "stop" a coroutine from outside you actually just tell Unity to remove the reference to that object. So the next state will never be executed.
If you look at it like cooperative multitasking, the Coroutine must give up control at some point, and nothing else is going to run until it does. So it's not being interrupted, it's letting itself be interrupted... which is better phrasing than "told to stop" :)
But yes, in a general usage sense it's being interrupted, so I'm with you when you look at it from that perspective.
Yes, each room has got a gameObject called Spawn$$anonymous$$anager, which instantiates the enemies and initializes them with a foreach loop within the Start() function; then it deactivates them with another for loop. Also, the enemies and their scripts are all enabled.
This is the piece of code:
void Start()
{
if (game$$anonymous$$anagerScript.dungeonSetting == Game$$anonymous$$anagerScript.DungeonSetting.fortress)
{
for (int i = 0; i < enemyDatabaseScript.enemyDatabaseList.Count; i++)
{
if (enemyDatabaseScript.enemyDatabaseList[i].dungeonType == EnemyScript.DungeonType.fortress)
{
clonedEnemy = enemyDatabaseScript.CloneEnemyByPosition(i);
spawnList.Add(clonedEnemy);
}
}
}
foreach (Transform child in transform)
{
int i = Random.Range(0, spawnList.Count);
GameObject enemy = (GameObject)Instantiate(Resources.Load("Prefabs/Enemies/" + spawnList[i].enemyName), child.transform.position, Quaternion.identity);
enemyList.Add(enemy);
Destroy(child.gameObject);
enemy.GetComponent<IInitializeEnemy>().InitializeEnemy(enemyLevel, spawnList[i].enemyHealthPoints, spawnList[i].enemyDefence);
}
for (int i = 0; i < enemyList.Count; i++)
{
enemyList[i].transform.parent = this.transform;
enemyList[i].SetActive(false);
}
}
So if I got it right: Frame 1: - the code instantiates the enemy - the Awake() function of the enemy is called (even before the enemy pops in the scene) and the code inside Awake() is done. - the interface function of the enemy is called and the code inside the function is done. - the code deactivates the enemy
Frame 2: - nothing happens, because the enemy has been alredy deactivated in the frame 1 and the Start() function doesn't start until the enemy is in the scene; the enemy could be in the scene during frame 2, but the code has deactivated it during frame 1, so there is no enemy and no Start() function.
Since you can't interrupt the code, is everything done during the same frame? And if the code takes a long time, is the next frame delayed until the code is done?
Thanks a lot.
Your answer
Follow this Question
Related Questions
Activate Game object when in Camera view and deactivate when out of camera view. 2 Answers
Most effective way to get deactivated children? 1 Answer
TransformPoint - different results in Awake() and Start() 0 Answers
problem with enable/disable on health script 1 Answer
Awake/Start/Update order 1 Answer