Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Creating draggable VisualElement and clamping it to screen?

Discussion in 'UI Toolkit' started by Crayz, Dec 6, 2020.

  1. Crayz

    Crayz

    Joined:
    Mar 17, 2014
    Posts:
    193
    My code works if the game resolution is the same as the reference resolution set in Panel Settings. If I could access the reference resolution somehow from within a VisualElement I would use that instead of Screen.width / Screen.height.

    Is there a way to do this without the reference resolution?

    Video:

    2020-12-06_12-00-09.mp4 (streamable.com)

    Code:

    Code (csharp):
    1. public class Draggable : VisualElement
    2. {
    3.     public new class UxmlFactory : UxmlFactory<Draggable> { }
    4.     private Vector2 _startPos;
    5.     private bool _dragging;
    6.  
    7.     public Draggable()
    8.     {
    9.         RegisterCallback<MouseDownEvent>(DragBegin);
    10.         RegisterCallback<MouseUpEvent>(DragEnd);
    11.         RegisterCallback<MouseLeaveEvent>(DragEndOnLeave);
    12.         RegisterCallback<MouseMoveEvent>(MouseMove);
    13.     }
    14.  
    15.     private void DragBegin(MouseDownEvent ev)
    16.     {
    17.         _dragging = true;
    18.         _startPos = ev.localMousePosition;
    19.     }
    20.  
    21.     private void DragEnd(MouseUpEvent ev)
    22.     {
    23.         _dragging = false;
    24.     }
    25.  
    26.     private void DragEndOnLeave(MouseLeaveEvent ev)
    27.     {
    28.         _dragging = false;
    29.     }
    30.  
    31.     private void MouseMove(MouseMoveEvent ev)
    32.     {
    33.         if (_dragging)
    34.         {
    35.             var delta = ev.localMousePosition - _startPos;
    36.             if (worldBound.x + delta.x < 0)
    37.             {
    38.                 delta.x = -worldBound.x;
    39.             }
    40.             else if(worldBound.xMax + delta.x > Screen.width)
    41.             {
    42.                 delta.x = Screen.width - worldBound.xMax;
    43.             }
    44.             if (worldBound.y + delta.y < 0)
    45.             {
    46.                 delta.y = -worldBound.y;
    47.             }
    48.             else if (worldBound.yMax + delta.y > Screen.height)
    49.             {
    50.                 delta.y = Screen.height - worldBound.yMax;
    51.             }
    52.             transform.position = transform.position + new Vector3(delta.x, delta.y, 0);
    53.         }
    54.     }
    55. }
     
  2. myzzie

    myzzie

    Joined:
    Feb 19, 2015
    Posts:
    13
    You'll need the bounds of the root or any element covering the screen. You could have a static reference of such element and get it's resolved width and height. That should fix your issue. If there's an easier way to find elements further up the tree I'd like to know. Iterating parents doesn't seem to stop at the root.
     
    Crayz likes this.
  3. Crayz

    Crayz

    Joined:
    Mar 17, 2014
    Posts:
    193
    I ended up with a base class inheriting VisualElement, from a MonoBehaviour I query elements implementing this class and give them the UIDocument reference. This way I have access to the root visual element and the panel settings.

    Not a bad solution, although it would be nice to accomplish it without leaving the scope.
     
  4. Crayz

    Crayz

    Joined:
    Mar 17, 2014
    Posts:
    193
    Quick update: I've found `panel.visualTree` which seems to be the root element covering the screen. Referencing its worldBound works.
     
    myzzie likes this.
  5. myzzie

    myzzie

    Joined:
    Feb 19, 2015
    Posts:
    13
    The UI Toolkit Debugger confirms that SettingsPanel is indeed the root. Thank you for that! Reading the manual on the visual tree it now makes sense.
     
    Crayz likes this.