0
\$\begingroup\$

I want to make a simple drag and drop card in Unity, where the card pops up a bit towards the screen when the drag begins (lifting effect), and then drops down back on the table when the drag ends.

My script looks like this:

public class Draggable : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
    {
        this.transform.position = new Vector3(this.transform.position.x, this.transform.position.y, this.transform.position.z - 10);
    }

    public void OnDrag(PointerEventData eventData)
    {
        this.transform.position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, -10);

    }

    public void OnEndDrag(PointerEventData eventData)
    {
        this.transform.position = new Vector3(this.transform.position.x, this.transform.position.y, this.transform.position.z + 10);

    }


}

The card is an image, and it is child of the canvas. The render mode for the canvas is Screen Space - Overlay.

The drag works correctly, but I cannot capture the movements in the z-axis.
It does capture the movements in the z-axis when I change the render mode. However, then the card is too far away in the z-axis, and it moves with an offset with respect to the mouse pointer.

As far as I understood, I need to do something about realtive distances, but I how can I force the mouse pointer to be on z=0 plane.

\$\endgroup\$
3
  • \$\begingroup\$ Are you looking for Camera.ScreenToWorldPoint, to transform a position on the screen to a position in your scene's coordinate system, based on the current camera view/projection? \$\endgroup\$ – DMGregory Jan 12 '20 at 15:57
  • \$\begingroup\$ @DMGregory So, I should not do it with Screen Space - Overlay render mode, right? \$\endgroup\$ – padawan Jan 12 '20 at 17:48
  • \$\begingroup\$ Your object is in a canvas, eh? In that case, you want to be working in your canvas coordinates, no matter what render mode you're using. \$\endgroup\$ – DMGregory Jan 12 '20 at 17:52
1
\$\begingroup\$

When the canvas is set to screen space overlay, the z isn't going to do anything as 'Screen space overlay' uses an orthographic camera which renders everything between z -1000 and z 1000 the same. It is not going to look like it is closer to the camera. That is just how an orthographic projection works..

I think you'd either want to set it to Screen space Camera and let a perspective camera render it, or edit the scale instead of the z position to fake it getting closer to the camera...

If you change the render mode however, your current drag code won't work as you already realized. This is because in 'screen space overlay' the canvas is scaled to this huge thing where the width and height of the canvas in world coordinates is equal to the width/height in pixels of the screen. Allowing you to set an items world position to a screen position without having to convert to world position first.

To convert to world space, I'd advise using RectTransformUtility.ScreenPointToLocalPointInRectangle. As this method is intended for usage in the UI system. I also use local instead of world position, to make it easier to edit the z without having to worry about the current rotation of the camera or position of the canvas. Result would look something like this:

public void OnDrag(PointerEventData eventData)
{
    Vector2 localPos;
    if (RectTransformUtility.ScreenPointToLocalPointInRectangle(transform.parent as RectTransform, eventData.position, eventData.pressEventCamera, out localPos))
    {
        transform.localPosition = new Vector3(localPos.x, localPos.y, -10);
    }
}

Where the -10 is replaced by a 0 in the end drag event.

\$\endgroup\$
3
  • \$\begingroup\$ Can I somehow do the same effect on mouse click, before the drag starts? \$\endgroup\$ – padawan Jan 12 '20 at 22:17
  • 1
    \$\begingroup\$ Yes, I think you mean by using the PointerDown event instead of BeginDrag? You can do that by implementing IPointerDownHandler and paste the same code as above in OnPointerDown. If you instead just want dragging to start earlier, you can also change the drag threshold of the EventSystem (the gameObject that is automatically added to your scene when you add a canvas) in the inspector. Note that this applies to all drag events though. \$\endgroup\$ – troien Jan 13 '20 at 12:44
  • \$\begingroup\$ Great! Thanks a lot. \$\endgroup\$ – padawan Jan 13 '20 at 15:47

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.