Search Unity

Event for when a gameObject is deactivated/activated?

Discussion in 'Scripting' started by Mister-E2, Aug 1, 2013.

  1. Mister-E2

    Mister-E2

    Joined:
    Jun 6, 2013
    Posts:
    179
    I can't seem to find anything in Unity script reference which refers to something like this. It seems a perfectly reasonable feature to add to the engine.

    I Have a menu system where I have buttons which take in a menu to activate/deactivate, which all works fine. The problem is, I want to make sure a certain function is called before one of the gameobjects is deactivated.

    Now I could do this using reflection and searching the method generically by type in my button script, but that seems overkill. Is there a hidden event that is not on the scripting reference to tell me when a go active state changes?

    I have also thought about writing a custom static function which I can call which will setActive an gameobject and allow me to do anything I want, but since I can't modify the unity core code and alot of my scripts are not connected to each other, this also seems like a lot of extra work for a simple thing.


    There is also the possibility I am missing something extremely simple, any help is greatly appreciated!
     
    _TheFuture_ and TheLagbringer like this.
  2. wolvz38

    wolvz38

    Joined:
    Feb 6, 2013
    Posts:
    66
    I assume your using the SetActive() function to activate/deactivate your gameobject... why can't you just call your function before that one? If you need a delay make a timer.
     
  3. Mister-E2

    Mister-E2

    Joined:
    Jun 6, 2013
    Posts:
    179
    Hey, thanks for the reply, the problem is, I am trying to keep my button object as clean as possible, and forcing it to rely on every object using it to contain a specific function is less than ideal. I need a way which keeps the entire thing generic, If that makes sense.
     
  4. Mister-E2

    Mister-E2

    Joined:
    Jun 6, 2013
    Posts:
    179
    Eli0uz, tendivided, Luis0413 and 17 others like this.
  5. wolvz38

    wolvz38

    Joined:
    Feb 6, 2013
    Posts:
    66
    Well once you call the SetActive() function it's going to do just that.. there isn't a way that I know of that can be like "Oh he wants to set the objects active state to false? lets let him know we are going to do this and wait for a confirmation before we do" lol that would just be silly. It's up to you to specify what you want to do before you change the active state of an object. If you want it to be cleaner you could write a new function that will call your function and delay your SetActive() and then just call that function instead... if that makes sense lol
     
    santiagolt likes this.
  6. wolvz38

    wolvz38

    Joined:
    Feb 6, 2013
    Posts:
    66
    Well in this case it's different, this would tell you when a script is disabled... and if you want something like that to check for a game object to be disabled you would just handle it with... if(gameObject.activeSelf == false)
     
    sami1592 likes this.
  7. Mister-E2

    Mister-E2

    Joined:
    Jun 6, 2013
    Posts:
    179
    You're right, but in my case this was the perfect solution as when I change menus, I deactivate the parent object which in turn disables all other gameobjects(and inherently their components) . If my entire gameObject hierarchy was deactivated, any component within would not be able to check if(gameObject.activeSelf) as you know.

    So ye, just thought I should explain why it was a good solution for me! Thanks.
     
    Botwillbat and MMOERPG like this.
  8. wolvz38

    wolvz38

    Joined:
    Feb 6, 2013
    Posts:
    66
    Okay cool, glad you found a solution that works for you :)
     
  9. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    I completely agree that some kind of generic event system that we can hook into for a wider variety of events would be excellent. However, in this case, I think that an ample solution would be to stick a listener component on the GameObject in question that does what you desire in OnDisable().

    Edit: Haha, I should have read the next few posts... silly!
     
    anrizald and twobob like this.
  10. Deleted User

    Deleted User

    Guest

    Sorry for the revival of a very old post, but I was looking just this thing and came to this post, which it didn't help me at first, but got me in the right direction. Now I have the correct answer and thought to post it for archive's sake and to help any future wanderer.

    To capture the Enabled/Disabled events of a GameObject you simply have to use OnDisable() and OnEnable() which they come with MonoBehaviour by default.
     
  11. elenzil

    elenzil

    Joined:
    Jan 23, 2014
    Posts:
    73
    this is the correct answer.
     
    icosajim and twobob like this.
  12. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    It isn't, actually, or at least no more than the previous answers. OnDisable() and OnEnable() are MonoBehaviour functions, not GameObject functions. That means that they check if the script/component is enabled or disabled, and not the GameObject itself. This could lead to false-positives when the script gets disabled and you treat it as if the whole object is.

    The correct answer was posted several years ago (several posts up) here. The answer is to use the OnDisable() and OnEnable() functions of the component in order to check the status of the GameObject, and then react if the entire thing has been disabled. Next time you should read to the end of the thread first IMO.
     
  13. elenzil

    elenzil

    Joined:
    Jan 23, 2014
    Posts:
    73
    ah, you're right. thanks for pointing that out.
     
  14. MMOERPG

    MMOERPG

    Joined:
    Mar 21, 2014
    Posts:
    50
  15. angryBits

    angryBits

    Joined:
    Mar 11, 2009
    Posts:
    1
    Very old thread...

    OnEnable() and OnDisable() are the right answer. It's generally better practice to not mutate the API if you don't have to, especially when you want your component to play nicely with a well established ecosystem and all the knowledge and expectations on top of it. Adding your own "setActive" method and then educating everyone about its purpose and how to use it, coding protection against misuse, it's not going to fly well.

    Anyway -- Post #12 was helpful for me. Good idea considering the state of the gameObject owning the Component :)
     
    MaxPirat likes this.
  16. utsav55501

    utsav55501

    Joined:
    Jul 4, 2016
    Posts:
    2
    thanks a lot it helped me a lot.
     
  17. feds

    feds

    Joined:
    Nov 8, 2017
    Posts:
    8
    My solution for that was not disable the game object but just make it invisible and do not receive the touch event anymore, my script below overrides both 3D objects and sprites, that way the object still having my event listeners and can appear and react accordingly.

    Use this to extend GameObject:

    // Do not use gameObject.SetActive(bool) because OnDisable() will stop the listeners
    public static void _SetVisibility(this GameObject gameObject, bool visible)
    {
    /*
    * For 3D Objects
    */
    Renderer renderer = gameObject.GetComponent<Renderer>();
    if (renderer != null)
    {
    renderer.enabled = visible;
    }

    Renderer[] renderers = gameObject.GetComponentsInChildren<Renderer>();
    if (renderers != null)
    {
    foreach (var r in renderers)
    {
    r.enabled = visible;
    }
    }

    Collider collider = gameObject.GetComponent<Collider>();

    if (collider != null)
    {
    collider.enabled = visible;
    }

    Renderer[] colliders = gameObject.GetComponentsInChildren<Renderer>();
    if (colliders != null)
    {
    foreach (var c in colliders)
    {
    c.enabled = visible;
    }
    }

    /*
    * For UI Sprites Object
    */
    Image image = gameObject.GetComponent<Image>();
    if (image != null)
    {
    image.enabled = visible;
    }
    }
     
    Clyde_Coulter likes this.
  18. Clyde_Coulter

    Clyde_Coulter

    Joined:
    Jul 14, 2014
    Posts:
    58
    Thanks @feds that worked for my situation. I was doing that sort of thing for my player gameobject (when dead and should be invisible), but that extension works great, like when using CullingGroup on objects that will be disabled and reenabled.
     
  19. jvlppm

    jvlppm

    Joined:
    Apr 3, 2018
    Posts:
    1
    You can use something like this:

    Code (CSharp):
    1. var listener = behaviour.gameObject.GetStateListener();
    2. listener.Disabled += () => Debug.Log("Object disabled!");
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public static class ObjectStateExtensions
    5. {
    6.     public static IStateListener GetStateListener(this GameObject obj)
    7.     {
    8.         return obj.GetComponent<ObjectStateListener>() ?? obj.AddComponent<ObjectStateListener>();
    9.     }
    10.  
    11.     public interface IStateListener
    12.     {
    13.         event Action Enabled;
    14.         event Action Disabled;
    15.     }
    16.  
    17.     class ObjectStateListener : MonoBehaviour, IStateListener
    18.     {
    19.         public event Action Enabled;
    20.         public event Action Disabled;
    21.  
    22.         void Awake()
    23.         {
    24.             hideFlags = HideFlags.DontSaveInBuild | HideFlags.HideInInspector;
    25.         }
    26.  
    27.         void OnEnable()
    28.         {
    29.             TryInvoke(Enabled);
    30.         }
    31.  
    32.         void OnDisable()
    33.         {
    34.             TryInvoke(Disabled);
    35.         }
    36.  
    37.         void TryInvoke(Action action)
    38.         {
    39.             if (action != null)
    40.                 action();
    41.         }
    42.     }
    43. }
     
  20. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    I'm having a similar problem but none of the suggested solutions work: when a GameObject is deactivated by an external script, I need any scripts attached to that GameObject to run "shut down" code before the script is deactivated, but OnDisable() doesn't work for some reason (either because it isn't run if the GameObject (but not the script) is deactivated, or because the GO is being deactivated by another, external script). Anyone know why OnDisable() isn't called in this case or what type of workaround is available?
     
  21. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    994
    OnDisable is fired in both cases for me. Are you running async stuff in your OnDisable? Is it capitalized fine? Can you post it!

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Fu : MonoBehaviour
    4. {
    5.     [SerializeField]
    6.     GameObject barObject;
    7.  
    8.     void Update()
    9.     {
    10.         if(Input.GetKeyDown(KeyCode.F))
    11.         {
    12.             barObject.SetActive(false);
    13.         }
    14.  
    15.         if(Input.GetKeyDown(KeyCode.G))
    16.         {
    17.             barObject.GetComponent<Bar>().enabled = false;
    18.         }
    19.     }
    20. }
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Bar : MonoBehaviour
    4. {
    5.     void OnDisable()
    6.     {
    7.         Debug.Log("Turns out I'm not FUBAR");
    8.     }
    9. }
     
    HonoraryBob likes this.
  22. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    Yes, it's capitalized correctly, and no there's no asynchronous stuff. Here's my code:
    Code (CSharp):
    1.     void OnDisable()
    2.     {
    3.         CurrentlyEquipped = 0;
    4.         SwitchEquipped (0);
    5.         SwitchOnOFF (0);
    6.     }
     
  23. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    994
    If you put a debug log at the top of the function, doesn't fire?
     
  24. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    I solved it - just another Stupid Programmer Error. The function was working, I just had things mixed up.
     
    ADNCG likes this.