- Home /
How can I move the mouse without moving the cursor? (Syringe Mechanic)
Hi everyone,
I have a Syringe in my game and the following behavior: The Syringe-Object follows the Mouse Position and when I click, I stop the Syringe from following the mouse and moving the mouse now presses the Plunger (which is part of / attached to the Syringe).
When I release the Mouse Button, unfortunately, the Syringe-Object makes a sudden jump because the mouse position changed. What I want, however, is to release the mouse button and have the Syringe stay at the same position as before.
How can I prevent this jump from happening? I already researched and found out that there is no native/cross-platform way to stop the cursor from moving.
Do you guys have any suggestions on how to move about?
Thanks for reading!
Answer by Bunny83 · Mar 17, 2015 at 05:22 AM
Like you already know there's no built-in (and therefore no cross platform) way to set the mouse cursor to a certain position besides the center (Cursor.lockState).
So if you need to set the mouse cursor to a certain position, you have to find a platform dependent way. For windows you have to use SetCursorPos (and maybe ClientToScreen) from the WinAPI. I don't work with other platforms (besides Android but it doesn't have a mouse ^^).
Of course there's no way to implement something like that in a webbuild.
edit
To implement a virtual mouse pointer all you need is to track the mouse delta and move a Vector3 around (could be a gameobject).
// C#
public float horizontalSpeed = 10f; // looks like "10" maps to the native speed
public float verticalSpeed = 10f;
public Transform cursorObj;
public bool allowCursorMove = true;
void CheckCursorLock()
{
if (Cursor.lockState == CursorLockMode.None)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
void Start()
{
CheckCursorLock();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
CheckCursorLock();
}
float h = horizontalSpeed * Input.GetAxis("Mouse X");
float v = verticalSpeed * Input.GetAxis("Mouse Y");
Vector3 delta = new Vector3(h,v,0);
if (allowCursorMove)
{
cursorObj.position += delta; // moves the virtual cursor
// You need to clamp the position to be inside your wanted area here,
// otherwise the cursor can go way off screen
}
}
This script will hide the hardware mouse cursor and instead moves a gameobject around according to the mouse delta. The gameobject could be anything, even a 3D object. Of course everything that involves a mouse position should use your virtual mouse position (the position of the cursor GameObject) from now on.
That could get a bit difficult with GUI stuff, but i think with the new UI system that should be doable. Just implement your own "PointerInputModule" derived module that doesn't use Input.mousePosition as the "StandaloneInputModule" does. Just use your virtual mouse position instead.
It's kind of impossible to use a virtual mouse position with the old GUI system (OnGUI).
To get the cursor right you have to consider the projection to the screen. The easiest would be to display an UI element in screen coordinates.
Thanks for your input. Unfortunately, I $$anonymous$$AY get that to work under windows but I also need it to work on $$anonymous$$ac & Linux so that's not a real option for me.
Do you know of any way to to "disable" the mouse while still tracking its x-axis / y-axis movement?
If there is absolutely no way to achieve that, I might have to implement the mechanic in a different way..
@kbm: No, not with Unity integrated tools as the hardware cursor is under OS control. There is an OS API (at least in windows) to restrict the hardware cursor to a certain screen rectangle, but it's still just a platform specific solution.
The only solution that will work on all platforms is to not use the hardware cursor at all like @Firelight mentioned below. However using Input.mousePosition still uses the hardware mouse position.
You have to track your own position and use the mouse delta to move that virtual mouse around.
I'll add an example to my answer.
The custom cursor that's supposed to imitate the mouse movement (using delta movement) indeed sticks with the mouse but only when it's moving at slow speeds. When I quickly move the mouse, the custom mouse and the system mouse are out of sync where the custom one is usually left behind. Any ideas?
@Sonoshee: The virtual mouse is never in sync with the hardware cursor since the hardware cursor should be locked (clamped to the center) while you only use the virtual cursor. If some delta information is skipped there's not much you can do about that. You don't have direct access to the message pump of the OS when developing in Unity.
$$anonymous$$ouse events are generated asynchronously and are usually stored in a message queue. An application usually polls the message queue the OS provides in the main loop (called the message pump). The main loop usually passes those events to the appropriate module / control / event listener so they can process them. If you move the mouse quickly the OS will generate a lot "mouse move" messages in a short time. Unity has to process those and pass the information on.
$$anonymous$$eep in $$anonymous$$d that most game engines work with raw data. So if you have a mouse acceleration setup in your system settings, the hardware cursor will move more than the actual move delta the mouse produced. The mouse delta is the real movement of the mouse and does not include any smoothing, adaptive acceleration or virtual boundaries which are applied to the systems cursor (depending on the OS settings).
Oh thanks a lot, this was really informative! I actually went with another strategy; since it's not possible to get mouse delta while the cursor is locked ( I mean lastPos - currentPos, not GetAxis), I left the cursor unlocked and whenever it exceeds a specific radius from the view center, I lock it and then unlock it so that it's reset to the view center. So far it's working really good. Thanks anyways for the clarification!
Answer by Firelight · Mar 17, 2015 at 02:35 PM
Yes, you can !
You should hide the default cursor
Than create a virtual cursor, which is just a 2d sprite you show where you want, we will position the sprite based on the mouse position (which you can still get even if it's hidden)
You can than clamp the "virtual cursor" to the screen.
// Use this for initialization
public GameObject cursor;
public Camera c;
void Start () {
Screen.showCursor = false;
}
// Update is called once per frame
void Update () {
Vector3 mousePos = Input.mousePosition;
Vector3 pos = c.ScreenToWorldPoint(mousePos);
cursor.transform.position = pos;
}
Answer by JanEricsson · Mar 31, 2015 at 03:08 PM
Since lockstate is disabled in Unity5 try this: http://answers.unity3d.com/questions/917677/center-cursor-and-toggle-on-and-off-unity-5.html
Screen.lockCursor
is deprecated in Unity 5 and was replaced by Cursor.lockState
, which in a way makes more sense because it is a cursor property.