When are IPointerHandlers executed in the Unity life cycle?

Hello,

Studying this execution order chart:

Where in this chart do we place the IPointerHandlers?

I thought it was included in the Input events, but after some testing that doesn’t seem to be the case.

It will be called somewhere in that loop of the execution order you posted above.

Since the docs for that interface don’t specify when it gets called, I recommend structuring your code so that it does not matter when it gets called. In other words, do very little work in the actual handler, just store the fact that it happened in local variables, and then process it as you see fit in Update() of timing is of critical importance to you.

Input events is certainly what I would have guessed. What did your tests show, exactly?

I don’t see how that helps. If you don’t know whether a given event happens before or after Update, then you might or might not be delaying your handling of the input until the next frame. If timing is important, that seems almost certainly worse than having uncertainty about when within a given frame it is being handled.

It’s not documented but I suspect it might just be in the middle of Update() somewhere, triggered from the EventSystem object’s Update method. You might be able to test this by creating two scripts at the extreme ends of Unity’s ScriptExecutionOrder, and one pointer handler, and see if a log from the pointer handler gets printer before both of the other scripts, in the middle of them , or after both of them.

Edit: Event System actually shows up in script execution order by default, so you can just wrap that:

1 Like

Those are the legacy OnMouseXXX events, which are no longer supported by the new Input System.

For IPointerXXX handlers, they are sent in the Input Module’s Process method, which gets called by the Event System during Update.

Which means the order of these input callbacks in regards to other Update methods is undefined. If you need explicit ordering, change it in Script Execution Order settings (you can’t change the Event System’s you have to change your scripts’).

I just ran some tests because it didn’t show up in my version (2018 LTS). So my initial assumption was they’d manage it internally in order to save you from trouble - i mean, the input you receive during a frame was gathered during the last frame, if you could change its order, you’d be able to add an extra delay of another frame- that’d be unfortunate.

Turns out that was a silly assumption. You can mess it up, the built-in event system is just running with a default seo of 0 in my version… Good to know, I’m wondering why I never cared about that before. :smile:

1 Like

My test was a flawed as it started mid life cycle and not from the beginning.

The test was with two buttons, Button A with infront of Button B.
Button A → IPointerClickHandler
Button B → IPointerEnterHandler

When clicking Button A a global bool is set true and the button disappears and Button B now receives the raycast.

When OnPointerEnter in Button B triggers it executes Debug.Log(“Is hovering”);

Then I had an IF statement in Update() to check if that bool was true.
If true, Debug.Log(“Bool is true”);

The resulting log was:

  1. Debug.Log(“Bool is true”);
  2. Debug.Log(“Is hovering”);

So, it seems in this test that the IPointerHandler event cluster had already been executed and was finished when we had finished clicking the button and setting the bool true, therefore the Update log triggered first.

My problem was that my logic was dependent on the IPointerHandler running before Update().

I solved it by moving my Update() logic to a Coroutine that waited for a frame with yield return null; and then to be safe I ran a yield return new WaitForEndOfFrame();
That made sure IPointerHandler executed once before hte “update()” logic.

I’d rather check the Script Execution Order in the settings (check @PraetorBlue 's screenshot).
Generally, you don’t want to mess too much with it, but as the input events from the event system are already based on physical input that was collected during the previous frame, it should most-likely be processed right away before you do most of the other stuff in that frame.

That’d be the clean solution IMO, and doesn’t require extra delays of that kind… imagine you had to do that for many more scenarios just because the events are fired “arbitrarily” somewhere in between all your components…, how annoying and messy would it get with all the coroutines?

1 Like