Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

c# events in OnEnable() and OnDisable() with Start() conflict

Discussion in 'Scripting' started by hexagonius, Jan 29, 2015.

  1. hexagonius

    hexagonius

    Joined:
    Mar 26, 2013
    Posts:
    98
    Hey guys,

    I have a little problem where I look for a better way to do this.
    I have two Gameobjects with one script each "InputManger" and "TouchObject"

    1. The InputManager assigns itself to its static singleton variable in Awake()
    2. "TouchObject" is grabbing this instance in Start()
    3. The "TouchObject" shall hook up to "InputManager"s events whenever OnEnable() is called and removes itself whenever OnDisable() is called.

    My only problem is the first time those delegates are ran, because OnEnable() comes before Start(). Right now I reverse the order by checking a bool, but is there a neater way to accomplish this?


    Code (CSharp):
    1. bool Init;
    2.  
    3. Start () {
    4.     if (!Init) {
    5.         Init = !Init;
    6.         OnEnable();
    7.     }
    8. }
    9.  
    10. void OnEnable(){
    11.     if (!Init)
    12.         return;
    13.     <<Do Stuff>>
    14. }
     
  2. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    How do you access the InputManager? Would it be possible to initialize the InputManager automatically in the case it is not initialized yet?
     
  3. Mycroft

    Mycroft

    Joined:
    Aug 29, 2012
    Posts:
    160
    I typically use Awake, instead of Start, when I need to initialize data because of issues like this.
     
  4. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,670
    You can't always use Awake() because there's no guarantee that the other GameObject/component has been initialized yet. I've seen this pattern used a lot:
    Code (csharp):
    1. private bool started = false;
    2.  
    3. void Start() {
    4.     started = true;
    5.     Hookup();
    6. }
    7.  
    8. void OnEnable() {
    9.     if (started) Hookup();
    10. }
    11.  
    12. void OnDisable() {
    13.     Unhook();
    14. }
    15.  
    16. void Hookup() {
    17.     // your hookup code here
    18. }
     
  5. hexagonius

    hexagonius

    Joined:
    Mar 26, 2013
    Posts:
    98
    So you're also using a bool to handle the starting sequence, that's fine to know.
     
  6. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
    If the GameManager isn't doing stuff on Update or OnGUI or any of the other methods that runs repeatedly, you should instantiate it when you need it instead of having it in the scene:

    Code (CSharp):
    1. public class GameManager : MonoBehaviour {
    2.  
    3.     private static GameManager _instance;
    4.     public static GameManager instance {
    5.         get {
    6.             if(_instance == null) {
    7.                 GameObject container = new GameObject("[GameManager]");
    8.                 DontDestroyOnLoad(container); //if neccessary
    9.                 _instance = container.AddComponent<GameManager>();
    10.             }
    11.             return _instance;
    12.         }
    13.     }
    14.  
    15. }
     
  7. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Return the instance in both occasions, inside the if and outside.
     
  8. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    What? Um...no....
     
  9. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Correct me if I am wrong, C# isn't my main ;p
     
  10. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    You're wrong :) What @Baste posted should work just fine.

    Whether or not it solves OP's problem is another question, but the code itself is sound.
     
  11. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Face palm, I thought it was @Baste with the issue *Facepalm*.
     
  12. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    The easiest way is to unsubscribe from the events right before you subscribe to them. Encapsulate that in a method.

    Here's the kind of thing I do:
    Code (CSharp):
    1. Action subscribeToEvents;
    2. void SubscribeToEvents() {
    3.     singletonEvent += M;
    4.     subscribeToEvents = null;
    5. }
    6.  
    7. void M() {}
    8.  
    9. void Awake() {subscribeToEvents = SubscribeToEvents;}
    10. void Start() {if (subscribeToEvents != null) subscribeToEvents();}
    11. void OnEnable() {if (subscribeToEvents != null) subscribeToEvents();}
    12.  
    13. void OnDisable() {
    14.     singletonEvent -= M;
    15.     subscribeToEvents = SubscribeToEvents;
    16. }
     
    Last edited: Jan 30, 2015
  13. hexagonius

    hexagonius

    Joined:
    Mar 26, 2013
    Posts:
    98
    @Baste Thanks for the hint, but I was talking about bypassing the call order of Unity's messages the first time they're called. And since I was talking about an InputManager, yes, I need that in the scene.
    @Jessy Thanks for that alternative