Screen.lockCursor breaks input

I’ve been trying to make a FirstPerson version of the PhysicsRaycaster. The idea is to use the Unity event system with objects in the world, so a first-person character can interact with them.

So I thought, simple enough, just alter the PhysicsRaycaster to cast from the middle of the screen, instead of from the mouse-location.

    // Code from PhysicsRaycaster.cs
    public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
    {
        if (eventCamera == null) return;

        //var ray = eventCamera.ScreenPointToRay(eventData.position); //old code
        var ray = eventCamera.ViewportPointToRay(new Vector3(.5f, .5f, 0f)); //raycast from the center
        ...

Add this to the first-person camera, and it works as expected. However, then I wanted to use “Screen.lockCursor = true;” to lock the cursor, then suddenly it didn’t work any more. The object didn’t get the proper events any more.

Event I found they didn’t get properly:
“Pointer Enter”. These were fired only when the pointer was on the object and I click (click-down).
“Pointer Exit”. These were only fires when I first got the “Pointer Enter” event in the way described above, and I then click outside the object.
“Drag”. Never fired.

“PointerDown”, “PointerUp” and “PointerClick” seem to work fine. I haven’t tested other events yet.

All these events work perfectly if I don’t use “lockCursor”, even with my altered code that raycasts from the middle of the screen.

What’s wrong?
I logged the eventData coming as a parameter in the Raycast method to see what’s going wrong. It seems its ‘pointerEnter’ value isn’t set properly when “lockCursor = true”. It’s only set when I click (mouse button down), which looks like the reason for it not working properly.
However, I couldn’t find why it’s not set properly. I’ve been looking in the source code, but couldn’t find anything. I’ll continue searching, but perhaps anyone here can help?

Note: I’m using https://github.com/tenpn/unity3d-ui to search through the source code, since Bitbucket doesn’t seem to have a proper search function to search in the files. I’m trying to track where the eventData’s variables are set, but haven’t found anything that could cause my problem yet. I also searched for the use of “lockCursor” but nothing came up.

Note 2: The idea is also to make a first person version of the GraphicsRaycaster for world-space canvases. This however has the same error, and I’m currently focussing on trying to fix the PhysicsRaycaster, I’m guessing fixing one will fix the other.

Thanks!

Update: I’ve found a fix for my problem. In the class ‘StandaloneInputModule’ there’s a method ‘UseMouse’, used to check whether or not a mouse event should be processed. This method doesn’t return true if the PointerEventData’s delta is zero (“pointerData.IsPointerMoving()”).

Disabling this check, and always processing mouse events (with a custom version of the StandaloneInputModule) fixes the problem.

However, I’m still wondering what others find. Is this a good way to fix it? Is there a better way? Perhaps a different way to make a first person controller or raycaster to work with the event system?

Ohh, so that’s what’s causing it. I can highlight my cube by bringing the mouse cursor on it, but if I bring the cube under the mouse instead, no reaction.

How did you write your custom StandaloneInputModule to override the default behavior?

You can get the source code for the default StandaloneInputModule here: https://bitbucket.org/Unity-Technologies/ui/src/5fc21bb4ecf4b40ff6630057edaa070252909b2e/UnityEngine.UI/EventSystem/InputModules/StandaloneInputModule.cs?at=4.6

I copied it into a file in my project “MyStandaloneInputModule.cs” and then edited it. The check I disabled is on line 245-246.
(Note: in the editor, your cursor will be locked slightly above the center of the screen, but in players it’ll be exactly in the middle.)

That’s how I started, by now I have changed much more but that’ll get you started.

1 Like

Thank you! That’s what I ended up doing. A bit overkill, I had hoped that overriding a public method would be enough. UseMouse always return True now; the microscopic performance impact totally worth it. I realize that the problem is not restricted to picking 3D objects: the current implementation won’t detect if a UI button is passing under a still mouse cursor.

Edit: Thanks for the warning about the pointer offset when playing in the editor, it’s happening to me as well.

Edit2: Argh. If I change the Viewport (camera rect so that the game view isn’t centered) then the invisible mouse is still picking things that are in the center on the screen, not in the center of viewport. I might have to implement my own Physical RayTracer to accept an offset.

I first made a custom raycaster as well, however it’s possible with only a custom input module, this way you can just use the default raycasters. There’s a class called “PointerEventData”, it has a position value, if you set that to the middle of the screen that’s what the raycasters will use.

I have posted my current implementation of my Input Module here: Current AdventureInputModule (not yet complete) - Pastebin.com
It’s heavily based on the StandaloneInputModule, however I stripped all the code for keyboard input to make it simpler. I changed some names of methods (‘Mouse’ became ‘Pointer’ or ‘Adventure’). I also made it a BaseInputModule, rather than a pointer, and copied the needed methods from that one (ProcessMove and ProcessDrag are the only ones.) And lastly I created a GetPointerEventData that gives the middle of the screen instead of the actual mouse position. There are other changes, but those are minor. Note however that it is still a work in progress, once it’s more complete and tested I’m planning to release it on github probably.

1 Like