Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by bowserscastle · Apr 27, 2018 at 02:20 AM · monobehavioursingletonorder-of-execution

Unexpected behavior - allowed to call method before Start() is called

I'm implementing object-pooling, though that's not the issue, and a bit confused about the order of operations between Monobehaviours. In the InitGame() method of MyGameManager, I call SpawnEnemy() on the EnemyManager singleton. What I would expect to happen (but is not happening) is for the Awake() method in EnemyManager to be called, then the EnemyManager-> Start() method, and then and only then, would SpawnEnemy() be called. What actually happens is that EnemyManager Awake() is called, then MyGameManager calls SpawnEnemy(), and when that's done, EnemyManager's Start() method is called last.

The docs say,

Start is called on the frame when a script is enabled just before any of the Update methods is called the first time.

I'm guessing that while my EnemyManager is Active, it is not Enabled, and thus it's Start() method is not called until after the call to SpawnEnemy(). I found it surprising that a method can be called on an object before Start() is called on that object.

I can work around this situation by simply including the line gameObject.SetActive(false); in my EnemyManager's Awake() method, and thus the SpawnEnemy() method will find and spawn an object from the pool, but it would be helpful to have a deeper understanding of when Start() is actually called. I've read the docs and whatever I could find, but don't feel like I fully understand.


Here is the Manager Singleton designed to easily create XxxxManager classes:

 using UnityEngine;
 
 public class Manager<T> : MonoBehaviour where T : MonoBehaviour
 {
     private static T _sharedInstance = null;
 
     public static T sharedInstance
     {
         get
         {
             if (_sharedInstance == null)
             {
                 _sharedInstance = Object.FindObjectOfType<T>();
                 if (_sharedInstance == null)
                 {
                     Debug.Log("Can't find " + typeof(T));
                 }
             }
             return _sharedInstance;
         }
     }

     public virtual void Awake()
     {
         // ...
     }
  }

An EnemyManager class:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class EnemyManager : Manager<EnemyManager>
 {    
     static private List<EnemyManager> enemyControllers;

     public EnemyManager SpawnEnemy(Vector3 location)
     {
 
         foreach (EnemyManager controller in enemyControllers)
         {
             if (controller.gameObject.activeSelf == false)
             {
                 controller.gameObject.transform.position = location;
 
                 // object available
                 controller.gameObject.SetActive(true);
                 return controller;
             }
         }
 
         Debug.Log("Not enough enemies available in pool.");
         return null;
     }
 
     public override void Awake()
     {
         if (enemyControllers == null)
         {
             enemyControllers = new List<EnemyManager>();
         }
 
         enemyControllers.Add(this);

         // If we SetActive(false) here, we DO get the desired behavior
         gameObject.SetActive(false); // <----- 
 
         base.Awake();
     }
 
     protected void Start()
     {
         // wake up and disable self
         // If we SetActive(false) here, we do NOT get the desired behavior
         gameObject.SetActive(false);  // <----- 
     }
 }

And I'm using these classes in MyGameManager:

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class MyGameManager : Manager<MyGameManager> {
 
     private EnemyManager enemyManager;
 
     public override void Awake()
     {
         enemyManager = EnemyManager.sharedInstance;
         base.Awake();
     }
 
     private void Start()
     {
         InitGame();
     }
 
     void InitGame()
     {
         enemyManager.SpawnEnemy(new Vector3(0, 0, 0));
     }
 }


Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by Harinezumi · Apr 27, 2018 at 07:23 AM

I know this confusion quite well, I have been there many times. The docs are very confusing, saying similar things, but somewhat cryptic. This is the best official description I've found so far: https://docs.unity3d.com/Manual/ExecutionOrder.html

In a nutshell, Awake() is called when the MonoBehaviour is instantaited (IF enabled), and Start() is only called on the first frame the object is already active, that is just before Update() is called on it for the first time (or would be called, if it doesn't have an Update()).
Or you could also say that Awake() is for internal initialization (it is the closest thing to a constructor), while Start() is for initialization with other components (when you can expect them to have correct internal state). At least, that's how I use it.

Finally, you can also modify the script execution order in Edit -> Project Settings -> Script Execution Order, where you can move scripts relative to the general execution time. Can be very useful if you have a primary manager class that needs it's Awake() to be called before everyone else's.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
2

Answer by ZuhairGhias · Apr 27, 2018 at 07:03 AM

That is likely happening because MyGameManager.Start() is called before EnemyManager.Start(). Therefore enemyManager.spawnEnemy() gets called. I don't think it is possible to determine which gameObject.Start() method is called first.

One thing you could try is putting your EnemyManager.Start() logic in EnemyManager.Awake().

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

83 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How do I fix this error when trying to use the Watson SDK for Speech to Text? 0 Answers

MonoBehaviour Inheritance, Singletons and Generics 1 Answer

Creating a list of singletons? 1 Answer

singleton becomes null? 0 Answers

How can I return a GameObject? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges