0
\$\begingroup\$

I wrote some code for a UI button that causes the mouse to avoid it. I realize this is kind of a weird thing to do in a game design-wise, but this is a really weird game. I need a button that is not only unclickable, but also unhoverable. I got it mostly working, but I cannot seem to change the position before the mouse is drawn, probably because mouse movement is handled by the OS, unless there is a problem with my code that I missed. As a result, pushing the mouse against the button boundaries results in a stutter. The mouse briefly appears over the button before I can move it, so it is still possible to click the button.

A demonstration of the button avoidance and stutter: https://youtu.be/7tgIrJ_vMDg

[DllImport("user32.dll")]
public static extern bool SetCursorPos(int X, int Y);
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out Point pos);

...

void Update () {
    var mousePos = Input.mousePosition;
    if (Application.isFocused && isOver) {

        //Get the current mouse position from OS so we can change it;
        Point cursorPos;
        GetCursorPos(out cursorPos);

        if (oldMousePos.x > xMin && oldMousePos.x < xMax)
        {
            //Coming from above or below. Figure out which one
            //and move mouse accordingly
            if (oldMousePos.y > uiPos.y)
                cursorPos.y -= (int)(rt.rect.height / 2 - (mousePos.y - uiPos.y));
            else
                cursorPos.y += (int)(rt.rect.height / 2 - (uiPos.y - mousePos.y));
        }
        else
        {
            //Coming from either left or right.
            if (oldMousePos.x < uiPos.x)
                cursorPos.x -= (int)(rt.rect.width / 2 - (uiPos.x - mousePos.x));
            else
                cursorPos.x += (int)(rt.rect.width / 2 - (mousePos.x - uiPos.x));
        }
        //Give new coordinates to OS to update mouse position
        SetCursorPos(cursorPos.x, cursorPos.y);
    }
    else
    {
        //track the old position to know what direction 
        //they moved their mouse from so we can put it back
        oldMousePos = mousePos;
    }
}

I tried using the Cursor API to force it to software mode thinking that might fix it, but it still stutters, and I would prefer to use the default cursor anyway, and hardware mode if possible. Is there any way to work around this or remove the stutter?

\$\endgroup\$
0
\$\begingroup\$

I’m guessing the problem is that you are changing the position of the mouse once per Unity frame (if you’re running at 60 FPS, that’s once every 16.67 ms), which is not the same timing that the OS uses to respond to the mouse moving.

My first thought would be to move the code in Update to run on a separate thread in a loop with no waiting. Note that you would be unable to interact with Unity APIs on this thread.

\$\endgroup\$
  • \$\begingroup\$ I tried what you said and put it on a thread with no wait, but it seems to have the same problem. \$\endgroup\$ – tyjkenn Oct 11 '18 at 0:59
0
\$\begingroup\$

Hide the system mouse cursor with Cursor.visible = false; in some method which runs at the start of your game. Then create your own mouse cursor by reading the mouse coordinates and moving a sprite to the given screen location.

By taking control of mouse drawing like this you also open up many more opportunities to screw with the player's perception of their mouse cursor. Just keep in mind that you are now responsible for making sure that the cursor's draw position matches the logical position. That means unless you want to also forego the Unity mouse event handling for the UI system and roll your own.

I'm looking forward to getting trolled by your game.

\$\endgroup\$
  • \$\begingroup\$ I assumed OP wanted to keep using the hardware mouse based on his comment about using the default cursor. This is certainly the better answer if that’s not the case, \$\endgroup\$ – Ed Marty Oct 10 '18 at 18:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.