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
0
Question by DaiMangouDev · Sep 18, 2015 at 08:16 PM · c#editorclasseditorscript

Is there a way to dynamically check for variable change ?

Hi guys .

I know how to check if a variable changes . One method is like this

         public class SomeClass
         {
 
             private Rect someRect;
             private Rect T;
 
             void OnEnable()
             {
                 if (someRect == null)
                 {
                 } someRect = new Rect(0, 0, 100, 100);
             }
 
             bool RectChanged()
             {
                 bool result = false;
                 if (someRect != T)
                 {
                     result = true;
                     T = someRect;
                 }
                 return result;
             }
             void OnGUI()
             {
 if(RectChanged())
 {
 Debug.Log("ChangeMade");
 }
             }
         }

However this method is really crude .

I need to be able to dynamically check for variable changes without having to do that kind o coding I will give you an example. this wont actually work well , it is just an example of what i'm trying to do.

if i were to create instances of this class in non static classes and make the method and variable non static then it would work well. However I do have class that I need to keep static which need to use the changed function.

         public  class Changed
         {
 
             private  static object obj;
 
             public static bool changed(object T)
             {
                 bool result = false;
                 if(obj != T)
                 {
                     obj = T;
                     result = true;
                 }
                 return result;
             }
         }


And use it this way

     public class TestClass
     {
         private static Rect someRect = new Rect(0, 0, 100, 100);

         public static void TestFunction()
         {

             if (Changed.changed(someRect))
             {
                 Debug.Log("change made");
             }

         }

     }

I figure that there is a high change of this being not possible but if you know of a way to do this then please share.

Comment
Add comment · Show 3
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 Glurth · Sep 19, 2015 at 01:53 PM 1
Share

I like your Changed class. I would modify it to store a list of ALL the objects you want to check, like so:

-$$anonymous$$ake the class static: so you can call functions like so- Change.RegisterObject(obj,function); always referencing the same single instance of the class.

-Add a main List to the class (replacing your object obj member)

-Add a notify List to the class. this list should match your main List, but it might be better to create a new class say..ChangeObjectAndAction that contains only an object and an action, and make a SINGLE List.

-Add a second List, that stores a COPY of all the objects in your main list. (this part can be a bit tricky, if you are not using basic class types like "string" and "int"- because you don't want a REFERENCE to the original, you want a copy of it's data: http://answers.unity3d.com/questions/501160/how-to-duplicate-a-gameobject-using-scripting.html)

-Add a registerObject() function, to add objects to the list, and a DeRegisterObject() function to remove them from the list. The registerObject function would take an Object, and an Action (reference to another function) as parameters, and add the object to your main list and a copy to your second list. It would also add the Action to the notify list.

-Add a compareAllObjects() function, in which you go through the main list, and compare all the values it contains with all the values in your second list. If you detect any mismatches, you can call the Action function you passed in when registering the object. Then set the value in the second list to equal the value of the first list, so they match for the next pass.

Disadvantage: The comparisons would be performed once per cycle, rather than immediately. Advantage: You don't need to modify or add any code when assigning a new value to a variable.

Let me know if you like this method and need more details or code examples.

avatar image DaiMangouDev Glurth · Sep 20, 2015 at 02:04 AM 0
Share

nice idea , i'm DEFINITELY going to give it a try and let you know how it goes .

If you already have it coded then you can post some code too.

$$anonymous$$y concern with this would be the speed of the code seeing as we would be using lists.

avatar image DaiMangouDev Glurth · Sep 20, 2015 at 08:20 PM 0
Share

This feels heavy , having to sort through the list continuously is a bit much. Too bad I cant use Dictionaries. This would be a bit heavy

2 Replies

· Add your reply
  • Sort: 
avatar image
6

Answer by Anxo · Sep 18, 2015 at 08:56 PM

I think you might be looking for events.

 public class ClassA : MonoBehaviour {
 public delegate void ChangeEvent (int numberOfApples); //I do declare!
 public static event ChangeEvent changeEvent;  // create an event variable 
 public int appleCount = 0;
 // trigger some change and call the event for all subscribers

 public void  MoreApples(){
   appleCount ++;
   if(changeEvent!=null) // checking if anyone is on the other line.
         changeEvent(appleCount);
 }
 
 }
 
 
 // Then you subscribe to the even from any class. and if the event is triggered (changed) then your other class will be notified.
 
 public class ClassB : MonoBehaviour{
   void OnEnable(){
      ClassA.changeEvent += ApplesChanged; // subscribing to the event. 
   }
 
   void ApplesChanged(int newAppleCount){
      Debug.log("newAppleCount now = " + newAppleCount);  // This will trigger anytime you call MoreApples() on ClassA
   }
 }
 }


WUCC, check for errors.

Comment
Add comment · Show 5 · 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 instruct9r · Sep 18, 2015 at 10:03 PM 0
Share

I wonder... are the Event heavy, from optimisation point of view? Like if you have 20, 30 events listeners in the game, coud that potentially affect the performance of the game...

I guess it's worth mentioning, that when you don't need to check for that variable anymore, you shoud un-subscribe, from the event.... I suppose that's done with -= AppleChanged right?

avatar image Anxo · Sep 18, 2015 at 10:11 PM 0
Share

correct. You also never want to call one with no subscribers without checking for null.

avatar image DaiMangouDev Anxo · Sep 19, 2015 at 01:09 AM 0
Share

@Anxo I'm not getting it .

         public class Check
         {
             public delegate void Changed (object T);
             public static event Changed changeEvent;
             public  object obj;
 
             public void $$anonymous$$akeCheck()
             {
                 Debug.Log("ran");
                 int I = 0;
                 obj = I;
                 if(changeEvent!= null)
                 {
                     changeEvent(obj);
                 }
             }
           
         }


  public class ClassB
         {
           static ClassB()
             {
                 Debug.Log("set");
                 Check.changeEvent += Check_changeEvent;
             }
 
            static void Check_changeEvent(object T)
            {
                Debug.Log("Change made");
            }
 
 }

When would I call Check.$$anonymous$$akeCheck() if it will only trigger.

In my editor window , If i have a Rect , int, string and I want to only want to print out a message once the values of any of those fields changes .

 public class ClassC : EditorWindow
 {
 
 // init editor window function here 
 
 private int SomeInt = 1;
 private String SomeString = "name";
 private Rect SomeRect = newRect();
 
 void OnGUI()
 {
 if(GUI.Button(new Rect(0,0,100,40),"Change Rect"))
 {
 SomeRect  = new Rect(UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20));
 }

// Once the Rhange Rect button is clicked then ...?? }

 }



I'm sorry , I'm just not used to this.

avatar image Anxo · Sep 19, 2015 at 12:09 PM 0
Share

When ever you change the value. I have not tried to subscribe in static classes / voids before but when you change the value here.

 new Rect(UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20));
 //Now trigger event
 Check.$$anonymous$$akeCheck(someobject); // you will need a reference to the class as its not static but you get what I mean right?
avatar image DaiMangouDev Anxo · Sep 19, 2015 at 08:54 PM 0
Share

@Anxo Sure thing I get it , and that would work. the big concern is that If we simply want the check to be continuous.

also Check.$$anonymous$$akeCheck doesn't take any parameters . So i'm writing this on the premise that i am missing something.

i.e void OnGUI() { // keep checking for change here . if a change is made then do something

 }

I wouldn't be ale to call Check.$$anonymous$$akeCheck(someobject); without wrapping it in that if statement. which is the problem .

What you are saying makes a lot of sense if I am not wrapping the calling of the event method in an if statement. But how about when i want to so a continuous check ?

          public class Check
          {
              public delegate void Changed (object T);
              public static event Changed changeEvent;
              public static  object obj;
  
              public static void $$anonymous$$akeCheck()
              {
                  Debug.Log("ran");
                  int I = 0;
                  obj = I;
                  if(changeEvent!= null)
                  {
                      changeEvent(obj);
                  }
              }
            
          }
 
 
   public class ClassB
          {
            static ClassB()
              {
                  Debug.Log("set");
                  Check.changeEvent += Check_changeEvent;
              }
  
             static void Check_changeEvent(object T)
             {
                 Debug.Log("Change made");
             }
  
  }
 
 
 
 

Use

  public class ClassC : EditorWindow
  {
  
  // init editor window function here 
  
  private int SomeInt = 1; // not used in this example
  private String SomeString = "name";
  private Rect SomeRect = newRect();
  
  void OnGUI()
  {
  if(GUI.Button(new Rect(0,0,100,40),"Change Rect"))
  {
  SomeRect  = new Rect(UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20), UnityEngine.Random.Range(0, 20));
 
  Check.$$anonymous$$akeCheck(SomeRect ); // then Check_changeEvent in ClassB would be called.
 
  }
 
  Check.$$anonymous$$akeCheck(SomeString); // calls Check_changeEvent in ClassB continuously . Problem.
 
 }
 
  }

Basically Check.$$anonymous$$akeCheck wouldn't actually do what i need it to do , which is wait for the value of the parameter it (obj) to change before carrying out some function.

ins$$anonymous$$d calling Check.$$anonymous$$akeCheck only carries out a function regardless of if the value in its parameter is changed.

avatar image
2

Answer by Alanisaac · Sep 19, 2015 at 08:54 PM

If you're not feeling events -- A "wrapper" class that uses properties might be what you're looking for.

The class looks like:

 public class ChangeTrackingWrapper<T>
     {
         private T _value;
         private bool _hasChanged;
 
         public ChangeTrackingWrapper()
         {
         }
 
         public ChangeTrackingWrapper(T initialValue)
         {
             _value = initialValue;
         }
 
         /// <summary>
         /// Gets or sets the wrapped value.
         /// </summary>
         public T Value
         {
             get { return _value; }
             set
             {
                 if (Equals(_value, value)) return;
                 _value = value;
                 _hasChanged = true;
             }
         }
 
         /// <summary>
         /// Gets a flag indicating whether the wrapped value has changed.
         /// </summary>
         public bool HasChanged
         {
             get { return _hasChanged; }
         }
 
         /// <summary>
         /// Resets the changed flag.
         /// </summary>
         public void ResetChangedFlag()
         {
             _hasChanged = false;
         }
     }

Notes:

I think this generalizes your original example.

The magic happens in the Value setter. If the value isn't different, the setter doesn't do anything. But if the value is different, it will set the HasChanged flag to true.

You can initialize the class with an initial value, or let it be the default value (which is default(T)). It uses the generic for type safety, and isn't static, so you can use it in place of any field in a class that you'd like (see usage below). I wasn't sure if or when you wanted to "reset" that your object has changed, but I included a ResetChangedFlag() method on the class.

Usage:

 public class SampleClass
     {
         private ChangeTrackingWrapper<Rect> _myChangeTrackingWrapper;
 
         void OnEnable()
         {
             if (_myChangeTrackingWrapper == null)
             {
                 _myChangeTrackingWrapper = new ChangeTrackingWrapper<Rect>(new Rect(0, 0, 100, 100));
             }
         }
 
         void OnGUI()
         {
             if (_myChangeTrackingWrapper.HasChanged)
             {
                 Debug.Log("ChangeMade");
                 _myChangeTrackingWrapper.ResetChangedFlag();
             }
 
         }
     }

Static Usage

 public class StaticSampleClass
     {
         public static ChangeTrackingWrapper<object> MyStaticChangeTrackingWrapper = new ChangeTrackingWrapper<object>();
 
         public void MyMethod()
         {
             StaticSampleClass.MyStaticChangeTrackingWrapper.Value = new object();
             var hasChangedAsString = StaticSampleClass.MyStaticChangeTrackingWrapper.HasChanged.ToString();
             Debug.Log(hasChangedAsString); //Should log "true"
         }
     }

Comment
Add comment · Show 5 · 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 DaiMangouDev · Sep 20, 2015 at 03:45 AM 0
Share

for some reason Set wont run at all

  set
          {
              if (Equals(_value, value)) return;
              _value = value;
              _hasChanged = true;
          }

avatar image Alanisaac · Sep 20, 2015 at 04:03 AM 0
Share

I just tested this myself again. Works fine for me. Did you copy and paste the ChangeTrackingWrapper class fully?

What do you mean by won't run -- will it not compile, or does it have the wrong behavior?

avatar image DaiMangouDev Alanisaac · Sep 20, 2015 at 04:38 AM 0
Share

yeah, i copied it fully . I do not know why but nothing in set{} runs.

avatar image DaiMangouDev Alanisaac · Sep 20, 2015 at 08:00 PM 0
Share

@alfalfasprout Set does work.

problem is I am working in a static method

  public class StaticSampleClass
      {
          public static ChangeTrackingWrapper<object> $$anonymous$$yStaticChangeTrackingWrapper = new ChangeTrackingWrapper<object>();
  
          public static void $$anonymous$$y$$anonymous$$ethod()
          {
              $$anonymous$$yStaticChangeTrackingWrapper.Value = new object();
              var hasChangedAsString = $$anonymous$$yStaticChangeTrackingWrapper.HasChanged.ToString();
              Debug.Log(hasChangedAsString); //Should log "true"
          }
      }

Set wont be called now

avatar image DaiMangouDev Alanisaac · Sep 23, 2015 at 02:49 AM 0
Share

the example doesn't work at all . Not sure why

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

31 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

Related Questions

Initialising List array for use in a custom Editor 1 Answer

Distribute terrain in zones 3 Answers

Multiple Cars not working 1 Answer

Listen to Keyboard Events on EditorWindow 1 Answer

Creating a class wide array (c#) 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