- Home /
OnMouseDrag() distance traveled / delta
I have a simple goal: determine how much the mouse has moved since the last drag event. In other words, does Unity have a property somewhere that tells you the delta between the current mouse position and the previous position?
Alternatively, if I can't get that in OnMouseDrag() on a MonoBehavior, is there a way I can get at Unity's MouseDrag event which does have this info (.mousePosition and .delta)?
NOTE: I realize I could just calculate it all myself. That's easy enough, but that's not what I'm looking for. I want to know if Unity does it for me.
EDIT: For those coming here for a solution, here's a rough implementation to give you an idea of what you can do:
// Inside a MonoBehavior
private Vector3 lastMousePosition;
void OnMouseDown() {
lastMousePosition = Input.mousePosition;
}
void OnMouseDrag() {
Vector3 distance = Input.mousePosition - lastMousePosition;
Debug.Log("The mouse moved " + distance.magnitude + " pixels");
}
Note that if you want to control objects in game world space, you'll need to convert from screen space to world space via Camera.main.ScreenToWorldPoint(screenPoint).
Thanks to those that answered! I suspected there might not be a built-in for this, but it was worth asking.
for the efforts of putting your solution here for the future visitors. :-)
Answer by HarshadK · Jul 04, 2014 at 06:01 AM
AFAIK, there is no in-built function in Unity that will give you the delta distance of mouse drag.
You have to calculate the delta distance yourself. :-P
Answer by Bunny83 · Jul 04, 2014 at 07:11 AM
Actually there is a function that returns the delta ;)
Input.GetAxis("Mouse X") and Input.GetAxis("Mouse Y")
However the default sensitivity is set to "0.1" for both axes. To actually get the delta in pixel / frame you have to set it to "4" (don't ask me why) or simply multiply the result by 40 (40 * 0.1 == 4)
This script on a GuiText does move it around as expected:
void OnMouseDrag ()
{
if (Input.GetMouseButton(0))
{
guiText.pixelOffset += new Vector2(Input.GetAxis("Mouse X"),Input.GetAxis("Mouse Y"))*40f;
}
}
Of course moving 3D objects in a perspective view requires you to do some screen-space to world-space conversion with ScreenToWorldPoint since the mouse delta represents a screen-space-delta.
edit
ps: If you ment to get the distance / vector from the starting point of the drag to the currrent mouse position, then: no, that doesn't exist. That doesn't even exist in windows or any other system i know.
2. edit
You can however use a helper script like this:
// C#
// MouseHelper.cs
using UnityEngine;
using System.Collections;
public static class MouseHelper
{
private static Vector2 m_CurrentMousePos;
private static Vector2 m_LastMousePos;
private static Vector2 m_CurrentDelta;
private static Vector2[] m_DragStartVector = new Vector2[3];
private static Vector2[] m_DragVector = new Vector2[3];
private static int m_LastFrame = -1;
public static Vector2 mousePosition { get { Update(); return m_CurrentMousePos; } }
public static Vector2 lastMousePosition { get { Update(); return m_LastMousePos; } }
public static Vector2 mouseDelta { get { Update(); return m_CurrentDelta; } }
public static Vector2 GetDragStartPoint(int aIndex) { Update(); return m_DragStartVector[aIndex]; }
public static Vector2 GetDragOffset(int aIndex) { Update(); return m_DragVector[aIndex]; }
static MouseHelper()
{
// force initialization on first access
m_CurrentMousePos = Input.mousePosition;
Update();
m_LastFrame = -1;
}
static void Update()
{
if (m_LastFrame >= Time.frameCount)
return;
if (m_LastFrame < Time.frameCount-1)
m_CurrentMousePos = Input.mousePosition;
m_LastFrame = Time.frameCount;
m_LastMousePos = m_CurrentMousePos;
m_CurrentMousePos = Input.mousePosition;
m_CurrentDelta = m_CurrentMousePos - m_LastMousePos;
for (int i = 0; i < m_DragStartVector.Length; i++)
{
if (Input.GetMouseButtonDown(i))
m_DragStartVector[i] = m_CurrentMousePos;
if (Input.GetMouseButton(i))
m_DragVector[i] = m_CurrentMousePos - m_DragStartVector[i];
}
}
}
With this scirpt you can simply use:
void OnMouseDrag()
{
guiText.pixelOffset += MouseHelper.mouseDelta;
}
This script is a static class, so it doesn't need to be attached to a gameobject (it actually can't). It updates itself when you access one of it's properties or methods.
It provides:
- mousePosition - current mouse position. Same as Input.mousePosition
- lastMousePosition - mouse position of the last frame
- mouseDelta - mouse delta since the last frame
- GetDragStartPoint(int aIndex) - gets the point of the last mouse down for each button
- GetDragOffset(int aIndex) - gets the offset vector from the last drag event based on the starting point
Note: the delta values are only correct if you use at least one property every frame, otherwise it won't update. The deltas will be 0 if there is more than one frame between two updates. That just means that you'll loose the delta of the current frame (which can't be calculated without the information from the last frame).
Concerning the GetAxis solution, I actually have a game object that is moved according to the mouse delta position ( not exactly the mouse position). The problem is that the object moves slower when the mouse moves quickly. I don't know if that's related to the sensitivity of the axis or not. I'm using the GetAxis value like so :
transform.position += new Vector2(Input.GetAxis("$$anonymous$$ouseX"), Input.GetAxis("$$anonymous$$ouseY"));
Any ideas why the object doesn't move with the same speed as the mouse?
Answer by seandanger · Jul 04, 2014 at 06:11 AM
MouseDrag is only for interaction with Unity GUI elements, for use inside an OnGUI call. So unless you're needing the delta for something Unity-GUI related, such as a custom Editor, then you'll need to calculate the delta yourself.
Perhaps interesting to note: Unity's Touch class does include a deltaPosition property.
It is true that the Event class can only be used inside OnGUI, but that doesn't mean it's only for GUI interaction. You can use it for whatever you like. The callback name "OnGUI" is a bit misleading as a better name would be "OnEvent". Of course it's primarily ment for GUI but that doesn't restrict you in any way.
You could do something crazy like:
Vector2 delta;
void On$$anonymous$$ouseDrag ()
{
guiText.pixelOffset += delta;
// This is necessary since the EventType.$$anonymous$$ouseDrag event in OnGUI
// is only fired when the mouse moves, so the delta is never 0
delta = Vector2.zero;
}
void OnGUI()
{
Event e = Event.current;
if (e.type == EventType.$$anonymous$$ouseDrag)
{
delta = e.delta;
delta.y *= -1; // GUI is y inverted
}
}
The result is the same as the example in my answer. I wouldn't use this approach since it doesn't make much sense. However there are other cases where OnGUI is really useful. For example this has only one empty object in the scene with only one script attached and everything you see is done in OnGUI.