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)); } }
Start()onEnemyManager(or other Manager classes I create) is called before I start working with them? \$\endgroup\$