Search Unity

Start before Update except when?

Discussion in 'Editor & General Support' started by snoopbaron, Oct 13, 2009.

  1. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    If I add a GameObject with two components and add it to a scene the Awake, Start, and Update methods get called in this order:

    1. Components A B Awake
    2. Components A B Start
    3. Components A B Update

    If I make this same GameObject into a prefab and create using Instantiate() I get this order:

    1. Components A B Awake
    2. Components A Start
    3. Components A Update
    4. Component B Start
    5. Component B Update

    You cannot and should not depend on ordering of A and B for any individual method (Awake, Start, or Update).

    It seems you can rely on Awake for A B getting called before any Start or Update calls for either A B independent of how the GameObject is created.

    But you can only rely on Start getting called before Update gets called on that particular component, the Update method on another component that is part of the same GameObject may be called before all Components that make up a GameObject have had their Start method called.

    This means that if you use Component B from Component A (or vice versa) you cannot be sure if the other component is fully initialized when you first use it in your Update method as the other component's Start method may not have run. You can often work around this issue by moving initialization code from the Start method to the Awake method, but that defeats the benefits of the Start method. You can also "check" to see if a component has had its Start method called before using it the first time, but this also seems less than ideal.

    Is there a good reason why Instantiate doesn't call Start on all components in a particular game object before calling any Update method on any of the components that make up that game object? It seems like it would make initialization much simpler and consistent?

    Am I going about this all wrong? How should I handle initialization code in Awake and Start when different components in the same GameObject reference each other?

    Thanks!
     
  2. Tempest

    Tempest

    Joined:
    Dec 10, 2008
    Posts:
    1,286
    One way to manage this would be to have a coroutine which is manages the startup code (in awake and/or start). Have one manager script/object which ensures that things are done in the right sequence. When it receives a return that the sequence is complete, then it flips a bool which allows Update to run.

    In my game, I have several 'managers'. a Manager ensures that the initialization is done on all the components/objects, and ensures that none of them proceed beyond initialization until it gives the signal.

    Awake and Start do have their benefits, but in a situation like your own I would recommend putting in your own systems to make sure multiple-component initialization goes exactly how you expect it too.
     
  3. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    Thanks for the help tempest. I do have manager objects for other things so I may use them to help deal with this. I'd really like to know if there was a good reason why Instantiate doesn't call Start on all components in a GameObject before calling the first Update on any of them as it does with Awake. It's always nice when you can keep simple things simple.
     
  4. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Interestingly, the doc page for MonoBehaviour says that Start should be called before any Update method gets called the first time. It might be a good idea to contact support@unity3d.com to get clarification on this.
     
  5. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    Thanks andeeee, I've sent an email to support. The documentation does seem ambiguous and could use some additional details to clarify this. It was this documentation that threw me off, and led me to look look at the call sequences of Awake, Start, and Update.

    "Start is called just before any of the Update methods is called the first time."

    The documentation is not technically wrong if you interpret "before any of the Update methods" to mean before any of the Update methods on this particular MonoBehaviour instance (ie. Update, FixedUpdate, LateUpdate for only this instance).

    I would like to know the reasoning for not calling Start on all MonoBehaviour instances of a GameObject before any Updates when using Instantiate. It's really useful when a scene is loaded that all Starts occur before any Update. As it is you can not guarantee for a GameObject created with Instantiate() that a particular monobehaviour is fully initialized (Awake + Start) if you refer to it from another monobehaviour's Update method. You can only be sure that when a particular MonoBehaviour's Update method is called its Start method will have already run.

    It would be nice if Instantiate could be changed to call "call all Awake methods, yield, call all Starts, call all Updates" instead of "call All Awake methods, yield, for each monobehaviour (call Start; call Update)." If it can't at least the documentation could be updated to make this more obvious.
     
  6. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Above both examples work like that and are fine actually

    As he instantiates the object himself in the second case, there is no object inter relation anymore, just the single independent instanced objects.

    The objects will only be synced in phases if they are in the scene at load time (who handles the phases then) and only that single time.
    If they are added later, they will basically only follow one order: awake -> start -> update on themself.
    anything that happens outside is not of their interest.

    That the awake of the second object slipped in there is likely because the rescheduling of the Start on the first object is postphoned to the second frame so the simulation runs once, as such the second instantiate triggers in and runs awake too.

    in the second frame then the first rescheduled object is called first again, so A Start happens and as start has happened it also gets update called.
    Then the second rescheduled object is beeing called so B Start happens and after that is through B Update can happen as well.

    Thats my understanding on how the whole system works basing on experiments with it and experience with various other single threaded scripting vms.
     
  7. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Ah... maybe I misunderstood the original post. I thought the issue was that two scripts on a single instantiated object were having Start and Update called unpredictably. Certainly, with two separate objects, there is no way to determine the order in which the methods should be called.
     
  8. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    andeee, you did not misunderstand my post. It's one game object with two scripts (two monobehaviour components). Not multiple GameObjects. For each monobehaviour you can of course rely on the awake, start, update sequence.

    dreamora, just to make sure we are on the same page, when you said that "just the single independent instanced objects." Are you referring to a single game object instance or multiple game object instances? I am referring to a single game object that has two MonoBehaviour script components attached. (When I say GameObject or game object I'm never referring to a MonoBehaviour)

    I've gone ahead and created a little test project that shows the behavior that I'm seeing. I've attached it to this post.

    While creating this test project I made a new observation. When I first tested this it was as part of a larger game project. In that project Instantiate was getting triggered when the player clicked on a game object. When I first wrote up this test project I instantiated the test game object in an Update method and found to my surprise that it consistently gave me the same sequence as on scene load:

    For a single GameObject with components A B:
    Component A Awake
    Component B Awake
    Component A Start
    Component B Start
    Component A Update
    Component B Update

    I then went back to my original game project and put the test print statements back in to check if I had made a mistake and this whole set of posts were a waste of time. But I got the same results as before. I then updated the test project and added a cube you could click on and tested instantiate from there. Using Instantiate from OnMouseDown gave me the same results that I saw in my game project every time:

    For a single GameObject with components A B:
    Component A Awake
    Component B Awake
    Component A Start
    Component A Update
    Component B Start
    Component B Update

    My game no longer depends on this ordering between Start Update, but I would like to have the documentation updated so others don't run into this and I would like to know why we can't have Start for both A B always run before Update for A B when A B are MonoBehaviour components of the same GameObject as I prefer that behavior for the reasons I gave earlier.

    Thanks again guys, it really helps to have someone to talk to about this. Sorry for my lack of clarity. Run the attached project and I think we will all be on the same page.
     

    Attached Files:

  9. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    Just a note:
    Awake
    Start
    Update

    Are all object dependent, not interobject dependent. Every object has those (and other methods) available to them, but that is the order in which things happen per object. When the game first starts, the Awake happens on all objects in the scene, then who's start happens when is up to which ever order they were in queue from Awake. All Unity does, is build a list of all objects when the scene first loads, then walks that object tree executing the Awake on frame 1 for any original objects of that scene, after that tree is built, they simply walk it in order for the Starts and Updates, but this doesn't mean that all Starts will happens at one swipe then all Updates in one swipe, it just means that before an objects Update happens, its Start will happen, that is all.

    When you instansiate an object in a running scene, it has its awake independent of the original list, and its start and update are also independent of the original list. It should be on the object stack though.
     
  10. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    Thanks zumwait, I'm aware of the distinction. But on scene load what happens is on frame 1:

    For two GameObjects (A B) each with two MonoBehaviour components (A B):

    Awake phase:
    GameObject A->MonoBehaviour A->Awake
    GameObject A->MonoBehaviour B->Awake
    GameObject B->MonoBehaviour A->Awake
    GameObject B->MonoBehaviour B->Awake

    Start phase:
    GameObject A->MonoBehaviour A->Start
    GameObject A->MonoBehaviour B->Start
    GameObject B->MonoBehaviour A->Start
    GameObject B->MonoBehaviour B->Start

    Update phase:
    GameObject A->MonoBehaviour A->Update
    GameObject A->MonoBehaviour B->Update
    GameObject B->MonoBehaviour A->Update
    GameObject B->MonoBehaviour B->Update

    The order between A B GameObjects and A B MonoBehaviours at each phase is of course not something you can or should depend on. But on top of the regular Awake, Start, then Update order you always have for each individual MonoBehaviour you also have an Awake, Start, and Update "phase" during scene loading.

    This is matches what I got from Unity support, so it is intended and not incidental that scene startup has its own Awake, Start, Update sequence on top of the Awake, Start, Update sequence of individual MonoBehaviours: "To clarify, the order of execution is Awake(), Start(), Update() - and they will get called in that order for all MonoBehaviours. One thing to note though, is that you can only count on this order for all the MonoBehaviours that are present in the Scene at startup."

    What I want clarification on is why for a single GameObject instance we get the same Awake, Start, Update phases between its constituent MonoBehaviours when it is instantiated from an Update method, but not when it is instantiated from OnMouseDown. If this lack of consistency is by design, I would like it documented, and if possible I would prefer to have Awake, Start, Update called in phases for a particular GameObject for the reasons I gave earlier (ie. make instantiating from OnMouseDown consistent with instantiating from Update (see my project for an example)).
     
  11. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    Here is an example of a pattern that will only work if OnMouseDown() {Instantiate(prefab); } worked the same as Update() { Instantiate(prefab); }.

    Imagine MyGameObject has two components ComponetA and ComponentB that depend on one another.

    ComponentA.js:
    Code (csharp):
    1.  
    2. private var componentB : ComponentB;
    3. private var someData : Object;
    4.  
    5. function Awake() {
    6.   // can't init componentB reference because A maybe created before B
    7. }
    8.  
    9. function Start() {
    10.   // both component A  B will have been created by the time any Start runs
    11.   // lets cache a reference here
    12.   componentB = GetComponent(ComponentB);
    13.  
    14.   someData = InitSomeData();
    15.   // after Awake  Start ComponentA is fully initialized and ready for its
    16.   // first update
    17. }
    18.  
    19. function Update() {
    20.   // this can fail if we are Instantiated from OnMouseDown as componentB
    21.   // might only be partialy initialized (Awake is gauranteed but not Start)
    22.   componentB.MethodB();
    23. }
    24.  
    25. function MethodA() {
    26.   // calling MethodA before ComponentA is fully initialized by Awake+Start
    27.   // will result in a null reference exception
    28.   someData.doSomething();
    29. }
    30.  
    ComponentB.js
    Code (csharp):
    1.  
    2. private var componentA : ComponentA;
    3. private var someData : Object;
    4.  
    5. function Awake() {
    6.   // can't init componentA because B maybe created before A
    7. }
    8.  
    9. function Start() {
    10.   // both component A  B will have been created by the time any Start runs
    11.   // lets cache a reference here
    12.   componentA = GetComponent(ComponentA);
    13.  
    14.   someData = InitSomeData();
    15.   // after Awake  Start ComponentB is fully initialized and ready for its
    16.   // first update
    17. }
    18.  
    19. function Update() {
    20.   // this can fail if we are Instantiated from OnMouseDown as componentA
    21.   // might only be partialy initialized (Awake is gauranteed but not Start)
    22.   componentA.MethodA();
    23. }
    24.  
    25. function MethodB() {
    26.   // calling MethodB before ComponentB is fully initialized by Awake+Start
    27.   // will result in a null reference exception
    28.   someData.doSomething();
    29. }
    30.  
    I think this would be something nice to have if it is technically feasible to Update Unity to support it. I've worked around the lack of this when creating an object from OnMouseDown, but I'd like to see it changed in the future.[/code]
     
  12. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    Let me attempt to make my case one more way.

    Unity's architecture wisely uses a composition model over an inheritance model for its GameObjects. The individual components in effect define the GameObject. Since a GameObject is a single logical entity made of components and defined by those particular components it makes sense that the GameObject is fully initialized (Awake + Start called on all its subcomponents) before it is first used (first Update for any component). To give a concrete example imagine a Robot GameObject it makes sense for all its components (head, motor, arms, gears, etc.) to be fully initialized (Awake+Start) before the Robot starts walking (Updates). I think this should be preserved whether the Robot is created as part of a scene load or Instantiated at runtime. I think it is more consistent with the architecture and more elegant and simple.

    I'm having a hard time putting into words exactly what I mean, but I hope this helps to clarify things a little bit.
     
  13. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    I did a quick test to see what would happen with a prefab that consisted of a tree of GameObjects instead of just a single GameObject.

    What I found is if you Instantiate a tree prefab all Awakes occur before all Starts which occur before all Updates independent of GameObject in the tree. If you instantiate the prefab from OnMouseDown you get the same lack of phases I described earlier.

    I think it is unlikely that this use of phases across multiple GameObjects of the same prefab is there by mistake. I think it is there because of what I posted previously (but expanded to a multi-gameobject prefab).

    If you take my Robot example but instead of the Robot consisting of one GameObject with multiple MonoBehaviours it is instead represented as multiple GameObjects in a hierarchy each with multiple MonoBehaviours then it makes sense for this prefab entity to be treated as a logical whole during its initialization when created by Instantiate. Therefore I believe the behaviour we currently have when calling Instantiate(prefab) from OnMouseDown is likely a bug. If it isn't it seems like a design flaw to me.
     
  14. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    I just wanted to drop in and say I've been following this thread and I think the behaviour you are seeing with multiple instantiated objects is very strange. I conferred briefly with Mike on the IRC channel (author of the Updated event execution order page on the wiki) and he not only agrees that what you are seeing is weird, but he wasn't able to reproduce it when he tried. You might want to drop by #unity3d on irc.freenode.net and see if you two can figure anything out.
     
  15. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    Thanks Daniel. I was just hanging out on #unity3d last Friday but didn't know the author of that page hung out there. I've found his wiki entry really useful while learning Unity. If you download the test project that I posted you will see that it also shows an example where this is not true:

    My test project prints out the current frame with each print statement and I get this:

    When instantiating from Update():
    Instantiate prefab: frame n
    Awake: frame n
    Start: frame n
    Update: frame n+1

    When instantiating from OnMouseDown():
    Instantiate prefab: frame n
    Awake: frame n
    Start: frame n
    Update: frame n

    Perhaps something has changed in Unity since he documented the event execution order?

    I'll see if I can find him on #unity3d. I recommend anyone who is interested in this to download the sample project and try it. I'm running Unity v. 2.5.1f5. If you run it let me know what results you are getting as I've only run this on my mac dev box.
     
  16. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    Just noticed another instance where what I'm seeing is not matching his observations:

    On frame one an obect that was already part of the scene is printing:
    Awake: frame 1
    Start: frame 1
    Update: frame 1

    I remember a while back when I was learning the Unity life cycle and reading the wiki I tested it and Start was getting called at frame n+1, just as he documented it, but it seems to no longer be the case!

    This all makes a good case for Unity to have a section in the official documentation that covers the event execution order/life cycle of the engine all in one centralized place.
     
  17. Sat

    Sat

    Joined:
    Aug 2, 2012
    Posts:
    4
    Hello,
    I have the exact same problem as described in the original post. Did you guys ever found the answer / solution?
     
  18. mslabs

    mslabs

    Joined:
    Jul 29, 2014
    Posts:
    2
    We also have recently noted The issue on one of our projects. Unity Version 4.6.3f1.
    Edit: Referring to the original posters issue.
     
    Last edited: Mar 19, 2015
  19. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    842
  20. mslabs

    mslabs

    Joined:
    Jul 29, 2014
    Posts:
    2
  21. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
    Wouldn't it be better to open a new thread? This one is 6 years old and might no longer be of relevance.
     
  22. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    842
    I read the thread, but you are not clear which of the mentioned issues your real problem is, so I guided you to the execution order, since it gives a rough overview