Search code examples
c#unity-game-engineunity3d-ui

Unity3D UI, calculation for position dragging an item?


These days it's incredibly easy to drag UI elements in Unity: Make a few UI items. Add Component -> Event -> Event Trigger. Drop on the script below. Click to add the four obvious triggers. You're done.

However.

I'm totally lost in the relationship between pointer coordinates and UI coordinates (as seen in RectTransform and so on).

In DragIt below: how the hell do you move a UI panel correctly under the finger?

Say you have one large panel, with ten UIButton sitting in the panel with Dragster on the buttons. What is the relationship between the RectTransform coords and the mouse pointer ...

in short how do you move one of the button around at DragIt() below?

/* modern Unity drag of UI element */
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class Dragster:MonoBehaviour
    {
    public int index; // number each of your UI items
    static bool beingDragged = false;
    static int dragFrom;
    public void DragStart()
        {
        beingDragged = true; dragFrom = index;
        }
    public void DragIt()
        {
        ? ? W T F ? ?
        }
    public void DragEnd()
        {
        beingDragged = false;
        }
    public void DroppedBra()
        {
        Debig.Log("Drag: from/to " +dragFrom +" --> " +index);
        }
    }

Solution

  • For Draging stuff I just do this :

    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    
    public class Draggable : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {
        
        
        
        public void OnBeginDrag(PointerEventData eventData) {
            
        }
        
        public void OnDrag(PointerEventData eventData) {
            //Debug.Log ("OnDrag");
            
            this.transform.position = eventData.position;
    
            }
    
        public void OnEndDrag(PointerEventData eventData) {
            Debug.Log ("OnEndDrag");
        
        }
    }
    

    Here's the identical amazing URIPOPOV CODE with two simple features which you always need when dragging:

    // allow dragging with two basic problem fixes:
    // - limit drag to the parent box
    // - don't "jump" based on where you hold down
    

    100% tested:

    Note that you MUST USE the scale conversion code from #programmer below.

    using UnityEngine;
    using UnityEngine.EventSystems;
    
    public class AmazingUPDrag : MonoBehaviour,
                   IBeginDragHandler, IDragHandler, IEndDragHandler
    {
    
    RectTransform rt;
    Vector2 dragOffset = Vector2.zero;
    Vector2 limits = Vector2.zero;
    
    Canvas canvas;
    
    void Awake()
    {
        rt = GetComponent<RectTransform>();
        canvas = GetComponentInParent<Canvas>();
    }
    
    public void OnBeginDrag(PointerEventData eventData)
    {
        dragOffset = ActualPos(eventData.position) - (Vector2)transform.position;
        limits = transform.parent.GetComponent<RectTransform>().rect.max;
    
        limits.x = limits.x - 100f;
        limits.y = limits.y - 100f;
    }
    
    public void OnDrag(PointerEventData eventData)
    {
        transform.position = ActualPos(eventData.position) - dragOffset;
    
        var p = transform.localPosition;
        if (p.x < -limits.x) { p.x = -limits.x; }
        if (p.x > limits.x) { p.x = limits.x; }
        if (p.y < -limits.y) { p.y = -limits.y; }
        if (p.y > limits.y) { p.y = limits.y; }
        transform.localPosition = p;
    }
    
    public void OnEndDrag(PointerEventData eventData)
    {
        dragOffset = Vector2.zero;
    }
    
    Vector2 ActualPos(Vector2 unityDelusionPos)
    {
        Vector2 p;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            (RectTransform)(canvas.transform),
            unityDelusionPos,
            canvas.worldCamera,
            out p);
        return canvas.transform.TransformPoint(p);
    }
    
    
    }