Is there any monobehaviour for when an object is modified/transformed? how to avoid polling?

I hate polling for changes, and repeating redundant actions. having to do it so often is really annoying.

I rarel use the update function if i don’t have to, most often i’m going for a coroutine with a lower poll interval, but it still annoys me. There has to be a better way

Is there any way to setup some kind of monobehaviour, event, etc that only triggers when something happens to an object? maybe when it transforms, or maybe even any change at all to its visible state. I don’t know, give me something.

//...

public int someInt = 0;
private int oldSomeInt;

void Start()
{
    oldSomeInt = someInt;
}

void Update()
{
    // if there was a change in someInt compared to its old value
    if(someInt != oldSomeInt)
    {
        // perform some action
        SomeAction();


        // update the old value
        oldSomeInt = someInt;
    }
}

void SomeAction()
{
    // do something...
}

Actually, it would be better to use a Property if you’re modifying a type you’ve declared yourself:

private int someInt;

public int SomeInt
{
    get
    {
        return someInt;
    }

    set
    {
        if(value != someInt)
        {
            SomeAction();
            someInt = value;
        }
    }
}

void SomeAction()
{
    // do something...
}

However the former method is good in situations where the change of something is out of your hands (i.e., Screen.width and Screen.height) since the change in that value is handled by Unity and there doesn’t seem to be any other way of being notified of when this kind of change happens.

void Update()
{
    // if there was a change in someInt compared to its old value
    if(someInt != oldSomeInt)
    {
        // perform some action
        SomeAction();


        // update the old value
        oldSomeInt = someInt;
    }
}

This is literally just polling, and worse than what i’m already doing with the delayed coroutines afaik

private int someInt;

public int SomeInt
{
    get
    {
        return someInt;
    }

    set
    {
        if(value != someInt)
        {
            SomeAction();
            someInt = value;
        }
    }
}

now this, i like. is there no way to apply it to transforms?

In either example, SomeAction can notify a list of registered users about the update. For example:

public List<Listener> listeners = new List<Listener>();

public void RegisterListener(Listener listener)
{
    if(listener != null && (!listeners.Contains(listener)))
    {
        listeners.Add(listener);
    }
}

void SomeAction()
{
    for(int i = 0; i < listeners.Count; i++)
    {
        listeners[i].SomeChangeOccurred(this);
    }
}

But of course you’d likely want to change the name of SomeAction to NotifyListeners and SomeChangeOccurred to Notify. Once a Listener is notified about the change, they can retrieve the changed value from the object that changed and store it and/or perform an action as a result.

It’s much easier to do this with Events, but since I am not completely comfortable with implementing Events I didn’t use them in this example. The concept is fairly similar, though.

Additional info I can’t emphasize enough that this is a Toy example strictly meant for describing the intention of why both methods are valid. To be completely honest, Listener should be a slightly more descriptive type for the class sending the notifications (i.e. SomeIntChangedListener : Listener) if you want to avoid having to cast the object being sent to SomeChangeOccurred. Also, you may want to send some information as to what changed (probably a 2nd parameter of SomeChangeOccurred, likely an enum that describes the change) but that is still specific to the class performing a change. I guess this is why Strings are commonly used as messages as opposed to Enums or Ints since they’re not as limiting.

I’ve said it before, but I guess I’ll say it again. Sometimes, polling cannot be avoided. This is the case if Unity doesn’t have innate notifications for something that changes (such as Screen.width and Screen.height), but at the very least you can isolate polling to one Monobehaviour that notifies its Listeners about the change. They can then update values based on the change and still continue to perform logic without having to constantly check a ‘value’ directly which may be a Property with additional overhead for accessing (i.e., uncached Transforms).

I could be wrong, but I think Transform is one such case where you would need to poll at least in one Monobehaviour and send notifications out to Listeners about the change in position, rotation, scale, or whatever you’re listening for specifically.

1 Like