Search Unity

Is there any way to "watch" variables?

Discussion in 'Scripting' started by Nanako, Nov 20, 2014.

  1. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    This is a noob question to be sure, but;

    to my mind, polling every frame to check something seems bad.
    But what if i have a public variable that can change at any time, and i need to know whenever that happens. Is there any way to trigger an event/monobehaviour when such a thing happens, so that i can then run what code i need to, rather than checking that value 60 times per second to ensure it's the same as it was the last thousand times i checked?
     
  2. Deleted User

    Deleted User

    Guest

  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Make the field private, have a getter/setter that wraps it, then you can run any code you want when it gets set.
     
    Nanako likes this.
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Note, if you're editing the value in the 'inspector', it will directly modify the field, and not call the property.

    But, if you have a custom editor written for it, you can make it instead call the property setter, or do something else as well.

    You could even go on to write a PropertyDrawer that does this every time, so you don't have to write a custom editor for every script that has a field that does this.
     
  5. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
  6. Stoven

    Stoven

    Joined:
    Jul 28, 2014
    Posts:
    171
    There are some cases where you may want to watch for something happening (i.e. Screen size changing), but when the change occurs is in Unity's hands and not yours.

    In that case, centralizing the polling to one behavior and notifying any registered watchers when a change happens is an alternative solution, using events like what was mentioned.
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Note .Net has a standard they use through out their framework for objects whose properties notify. You don't have to, but it's always nice to stick to those standards. That way if they release any tools that hook into those standards, you automatically get them.

    In this case, the standard uses the 'INotifyPropertyChanged' interface as a contract:

    http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.90).aspx

    Your object implements this, which defines the event that will be dispatched. As you can see in the example on there they add their object to a BindingCollection, this is one of those tools in the .Net library that hooks into this standard.
     
    makeshiftwings likes this.
  8. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I like using getters and setters for this. Each change you make has to pass through your own function for it, so you can perform validation and so on.
     
    Stoven likes this.
  9. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    this. you don't need events.
     
  10. RSG

    RSG

    Joined:
    Feb 20, 2013
    Posts:
    93
    I like to use properties with events; you end up writing more code but you know precisely when a value changes and you don’t have to perform checks on every frame. example:

    Code (CSharp):
    1. public int MyValue
    2.     {
    3.         get { return _myValue; }
    4.         set
    5.         {
    6.             // Ignore if value has not changed
    7.             if (_myValue == value) return;
    8.      
    9.             _myValue = value;
    10.      
    11.             // Send message to indicate that value has changed
    12.             if (this.OnMyValueChanged != null)  this.OnMyValueChanged(value);
    13.         }
    14.     }
    15.  
    16.     private int _myValue;
    17.  
    18.     /// <summary>
    19.     /// Occurs when the <see cref="MyValue"/> property changes.
    20.     /// </summary>
    21.     public event Action<int> OnMyValueChanged;
     
  11. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    No one "needs" events, but they certainly are helpful if you want to track whether something changed from a bunch of different classes. Otherwise you need to reference all possible other classes that might need to know within the setter, which can quickly become impossible to maintain.
     
  12. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    yes of course.
     
  13. Zoodinger

    Zoodinger

    Joined:
    Jul 1, 2013
    Posts:
    43
    The problem with events is that they don't serialize well, so if you want to use them you have to go some extra steps to make sure they're working. If you don't do that, changing the code while your game is running will mess everything up.

    Like everyone said, you can just use properties that use a private backing field. Put [SerializeField] right before that backing field to make it show on the inspector.

    Code (CSharp):
    1. [SerializeField]
    2. private int _backingField;
    3.  
    4. public int Field {
    5.     get { return _backingField; }
    6.     set {
    7.         Debug.Log("Field set to " + value);
    8.         _backingField = value;
    9.     }
    10. }
    Note that your setter will not be called if you change the value on the inspector.
     
  14. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    I also find that it can be handy to put certain values up on the screen using OnGUI().

    This is a little extra work to set up for a given object, but you can even see what is happening (for example) when running on mobile without a debugger.

    To give you an idea, let's say you have a door-opening script that is failing in some way.

    You can put a void OnGUI() method in your script that:

    - checks the distance to the player to make sure you are "close enough"
    - when you are close, it displays on the screen (say in the upper left corner), a printout of the internal state of the door script, which may give you insight into your problems.

    I find it invaluable, sort of a throwback to the good old days of debug_printf() calls sprinkled throughout your code. :)