Search Unity

Unity UI [Solved] Getting position and size of RectTransform in Screen Coordinates

Discussion in 'UGUI & TextMesh Pro' started by esbenjon, Jan 27, 2020.

  1. esbenjon

    esbenjon

    Joined:
    Aug 20, 2018
    Posts:
    7
    Is there a prefered way to get the position and size of a RectTransform in Screen Coordinates, suitable for using in a script to compare with mouse clicks?

    This is an issue that I have struggled with a lot, trying to use Unitys UI system. There seems to be dozens of different solutions on the net, may of which seems overly complex for such a simple thing.

    I've tried converting to and from world space, which seems to work for Screen Space - Camera, but not in overlay mode, Using RectTransformUtility.
    I've tried using RectTransform.rect and called Canvas.ForceUpdateCanvases in the Start method, no luck either.
     
  2. esbenjon

    esbenjon

    Joined:
    Aug 20, 2018
    Posts:
    7
    I figured it out, I think :)

    I use transform.position for bottom left coordinates and transform.rect.height transform.rect.width to calculate the top right coordinates. My particular issue was that the pivot point of the y-axis was set to 1 and needed to be accounted for.

    I have no idea if this will work in all circumstances or if other variables than pivot point could affect this. I keep getting in trouble regularly doing these kind of calculations.
     
  3. eliGasious

    eliGasious

    Joined:
    Apr 7, 2015
    Posts:
    16
    Glad you found a solution, for anyone else googling this, here's another soulution for Getting Screen Coordinates from a RectTransform.

    As far as how/why your rect is performing the way it is check out https://docs.unity3d.com/ScriptReference/Rect.html

    Here are some solutions:

    Working off the base request
    Option A))
    Maths, RectTransform.anchorMax & anchorMin, and screen.width & height. With these vars you can get location and size parameters.
    Note that they are normalized which means they exist between 0->1 or we can see them as percentage across the vector where 1 = full width or height.
    Code (csharp):
    1.  
    2. float rectWidth = (yourRect.anchorMax.x - yourRect.anchorMin.x)*Screen.width;
    3. float rectHeight =(yourRect.anchorMax.y - yourRect.anchorMin.y)*Screen.height;
    4. Vector2 position = new Vector2(yourRect.anchorMin.x*Screen.width, yourRect.anchorMin.y * Screen.height);
    5.  
    6. //world pos, width and height, all points found thusly
    7. //create a new rect or redefine yourRect then we'll use
    8. Touch touch = Input.GetTouch(0);
    9. if(yourRect.Contains(touch.position))
    10. {
    11. //do stuff if touched
    12. }
    13.  
    Option B))
    There's a few steps, but it's quite easy and we only need three provided class methods and a loop or two.

    1.void RectTransform.GetWorldCorners(Vector3[] v);
    //where v is the Vector3 array to return the corners to in world coordinates.

    2.Vector3 Camera.main.WorldToScreenPoint(Vector3 p);
    //where p is the Vector3 point representing a corner

    and after using the two above to either create an abstract test region or refactor the ret we have to screen space coords, we check for touch using the same method as before.

    3.bool Rect.Contains(Vector3 testPoint)

    TO Future people, feel free to reach out if you need more help.
     
  4. Imhotebkin

    Imhotebkin

    Joined:
    Feb 10, 2015
    Posts:
    18
    The only one that actually works, thanks!
     
  5. novaVision

    novaVision

    Joined:
    Nov 9, 2014
    Posts:
    518
    Not perfect as it doesn't cover the case when size delta is set. Here is the unified approach


    Code (CSharp):
    1.  public static class RectTransformExtension
    2.     {
    3.         public static float GetWidth(this RectTransform rt)
    4.         {
    5.             var w = (rt.anchorMax.x - rt.anchorMin.x) * Screen.width + rt.sizeDelta.x;
    6.             return w;
    7.         }
    8.        
    9.         public static float GetHeight(this RectTransform rt)
    10.         {
    11.             var h = (rt.anchorMax.y - rt.anchorMin.y) * Screen.height + rt.sizeDelta.y;
    12.             return h;
    13.         }
    14.     }
     
  6. BjoernS

    BjoernS

    Joined:
    Nov 14, 2012
    Posts:
    5
    Thx, but also not perfect.
    If one want to get the size in screen pixels you have to mlutiply the scale factor of the Canvas (if it is set to scale with screen size)

    Code (CSharp):
    1. public static class RectTransformExtension
    2.     {
    3.  
    4.         public static Canvas GetCanvas(this RectTransform rt)
    5.         {
    6.              return rt.gameObject.GetComponentInParent<Canvas>();
    7.         }
    8.  
    9.         public static float GetWidth(this RectTransform rt)
    10.         {
    11.             var w = (rt.anchorMax.x - rt.anchorMin.x) * Screen.width + rt.sizeDelta.x * rt.GetCanvas().scaleFactor;
    12.             return w;
    13.         }
    14.      
    15.         public static float GetHeight(this RectTransform rt)
    16.         {
    17.             var h = (rt.anchorMax.y - rt.anchorMin.y) * Screen.height + rt.sizeDelta.y * rt.GetCanvas().scaleFactor;
    18.             return h;
    19.         }
    20.     }
     
    SolidAlloy and marie-hmm like this.
  7. Brian_X

    Brian_X

    Joined:
    Sep 21, 2021
    Posts:
    1
    All the "recent" answers did not work in my case. I believe this only works if you have a specific anchor. I have a stretched anchor on x and y, so the width and height is exactly the same as the screen resolution.