More transform callbacks

I happily noticed that you added onTransformParentChanged() to MonoBehaviour. In my opinion this doesn't go far enough and Unity would also need an onTransformChanged() callback. This kind of callback is necessary to keep proxies in synchronization with the game object. E.g. collision proxies, rigid bodies or update the navigation mesh to apply dynamic changes .

I am actually surprised that is not possible till now since it seems to be a basic feature of any game engine.

Thanks,
-Dirk

3 Likes

So you want OnPositionChanged(), OnRotationChanged(), OnScaleChanged(), OnTransformChanged()?? Where does it end? How about we do that for everything and have OnVelcityChanged(), OnAngularVelocityChanged(), OnMassChanged(), OnColliderSizeChanged(), OnDragChanged().

Daniel beat me to it. I agree it could lead to some nice event-driven/ change-driven code, but it would have to be far more generic than onTransformChanged() to be useful. Something like generic property binding could be really swell though. (i.e.: transform.position.bind(positionCallback)).

Daniel, say e.g. you have a custom collision system that maintains proxies in some acceleration structure. A classic way to implement this is to flag the proxy as 'dirty' when the position changes. Then whenever you perform a ray cast or volume query the dirty proxies are moved to the update location prior to performing the query. A lot of game systems like character movers or weapon hit detection rely on the proxies being at the correct location.

Of course I could just iterate over all shapes and test if its transform has been updated (e.g. using Transform.hasChanged()). I think we both agree that this becomes very unreasonable once the number of objects grow over some threshold.

We could of course move the responsibility to the user and whenever he moves the game object he is also required to move the corresponding proxies. I guess that we agree that this is highly impractical and error prone.

From my experience it is pretty usual in a game engine to receive a callback whenever the state of the hierarchy changes since it is such a central part of the engine. So I think an OnTransformChanged() callback passing an event type (e.g. position, rotation, scale) makes a lot of sense and from my experience is actually pretty common in game engines.

HTH,
-Dirk.

2 Likes

Who's changing the position? Have the object that is changing the position also call your other proxy system to notify it of a position change.

I actually mentioned this in my post. This is unpractical and error prone in my opinion. It actually creates unnecessary couplings between the proxy system and every other component in the game object that alters the position.

3 Likes

Dirk is absolutely right here. Having events for when the position/rotation/scale changes (and potentially other components as well such as colliders and rigidbodies) would be invaluable. It would be much more performant than manually checking transform.hasChanged every frame (which, for example, is a major source of performance issues in NGUI), it would reduce code coupling, and it would still work when we do not have access to the code that modifies the transform (such as with closed-source 3rd-party libraries, or even Unity’s animation system). It’s been a longstanding problem that Unity support callbacks like these.

6 Likes

I know this is an old thread, but seriously, it would be great to be able to write something like this:

gameObject.transform.Changed += OnTransformChanged;

Where OnTransformChanged could look something like this:

void OnTransformChanged(TransformChannel transformChannel)
{
   // Do stuff
}

TransformChannel could be defined as:

public enum TransformChannel
{
     Position,
     Rotation,
     Scale
}

Even without any parameters and it would still be awesome.

I am working on an editor extension in which I want to perform raycasts, overlaps etc without the Physics API. One aspect of this is that I need to know when the transform of an object has changed. Looping through all objects in the scene and checking the hasChanged property of its transform is plain silly.

Same goes for when an object is created or destroyed. Since game objects are the core entity in Unity, it seems absurd to not have any way of knowing when one is created in the scene or destroyed. You have to attach a script to your game objects to detect this and its annoying.

4 Likes

Absolutely love if this was possible..
Went ahead and submitted this in the feedback tool
https://feedback.unity3d.com/suggestions/transform-callback-events

Just a note to those listening to this thread, hasChanged does not strictly detect changes, it is just set to true when transform properties are set. e.g. transform.position = Vector3.zero; will set hasChanged to true even if position is already Vector3.zero. So if you need to detect true property changes, you'll need to perform your own comparisons.
https://docs.unity3d.com/ScriptReference/Transform-hasChanged.html

    public void Update()
    {
        if(transform.hasChanged)
        {
            transform.hasChanged=false;
            Vector3 currPos = (mTrackLocal?transform.localPosition:transform.position);
            if(mPrevPos!=currPos)
            {
                Debug.LogFormat("<b>POS CHANGE</b> {0}'s pos={1}->{2}, frame={3}", FullGOName(transform), mPrevPos, currPos, Time.frameCount);
                mPrevPos = currPos;
            }
        }
    }

Voted up for the feedback...

I have a number of components in many partial classes, attached at character controller. In some point it moved unexpectedly and it's really hard to find which script exactly do it...

Since the feedback site is no more I'm just going to say "+1"!

I've put together a tool that'll allow you to detect those changes with a very user friendly GUI built on top


You can get it on asset store!

There's also an open source component that does similar thing
https://github.com/handzlikchris/Unity.TransformSetterInterceptor

It's been nine years, and we still need this method. Nine years!

My use-case today: RectTransform is missing this callback, but has ALL the others (did the size change? did the parent change? did the children change?). This means that UI's CANNOT efficiently detect changes (this is, I believe, one of the reasons why Unity GUI is so sloooooow in editor when your GUI gets sufficiently complex: no-one can write any GUI code that fires "only" if something changed)

2 Likes

yikes!

FYI to anyone else reading this: I found a clever workaround for any cases involving SceneView (which is almost all the ones you end up needing).

For anyone to touch a transform in SceneView, by definition they will also have that transform selected in at least on Inspector (unless they closed all Inspector tabs, but that's very very rare - you can't use most of the Editor any more if you do that!). So: create a custom editor for any MB whose transform you need to track, and in OnInspectorGUI check on every update whether or not the transform is different to last time. This method is - by definition - called every time the user moves in sceneview, so you get your callback.

Unity could easily have implemented this themselves, at any time in the last 10 odd years.

Indeed, it is very strange that there is still no such necessary function.

Such a workaround does not suit me, because I have to track the position of objects in the game. I want to implement CullingGroup for dynamic objects (including rigidbody). To update the positions of the spheres, I could use a callback when changing the transforms of the objects, then this would not affect the performance as much as manually scanning each object in the list and checking its transform.hasChanged.

I wrote another request to the developers. Speak out there to demonstrate to developers that people still have an interest in adding this feature: https://forum.unity.com/threads/need-a-callback-when-changing-transform.890854/

I’ve put together a tool that could help, it allows you to add events directly to Unity dlls, so you can write code like

transform.SetPositionExecuting += (sender, e) => <your handler code>

You could quite easily customise which events are added it should still work if you want to add one for rectTransform.size, eg

rectTransform.SetSizeExecuting += (sender, e) => <your handler code>

Tool adds events directly to Unity dlls so there’s no code rewriting that happens on your assemblies.

Got some troubles with adding a link, just click on ‘G’ at begining of this like or look for Unity.MissingUnityEvents on github

Hope that helps.

1 Like

Sounds great for individual projects! Doesn't work for me, as most of my code is shared with other people - there's no way I can demand everyone hacks their DLL's to make my code work :). But for your own game, it sounds great.

I need a onTrasnformChanged to recalculate variables that are used to draw the gizmos/handles