Search Unity

Get real screen position for a canvas UI element

Discussion in 'Editor & General Support' started by viveleroi, Jan 5, 2017.

  1. viveleroi

    viveleroi

    Joined:
    Jan 2, 2017
    Posts:
    91
    I'm "tweening" a sprite from a spot in my 2d world to a specific point in my overlay/HUD. When needed, I create an Image on my UI canvas and tween it to 0, 0, 0.

    Problem is, I need to choose the correct screen position of another image, but can't seem to find the correct values.

    I have a canvas gameobject called HUDCanvas used to display my game's HUD. It's set to "Screen Space - Overlay" and defaults to a rect transform of x: 608.5, y: 371.

    I have an image on this canvas, called "Hotbar". It's anchored to x: 0.5, y:0 and has a rect transform position of x: 0, y: 44.

    Those display just fine, the anchoring works well across screen sizes.

    I want the destination of my "tween"ed sprite to be the "Hotbar" image. 0, 0 takes my tweened image to the bottom left corner of the window, no matter how I adjust the anchor. I can't figure out any coordinate system to make these all make sense. The "WorldToScreenPoint" position seems correct, the canvas and hotbar graphics show correctly, so I'm not sure what's missing.

    The hotbar position is x: 608.5 y: 44, it's localPosition is x: 0, y: 44.

    If 0, 0 for my tweened sprite is "lower left corner" then none of those coordinate systems are right.

    Code (csharp):
    1.  
    2. // Convert this world coord to a screen coord
    3. var camera = GameObject.Find("Main Camera").GetComponent<Camera>();
    4. var screenPos = camera.WorldToScreenPoint((Vector3)tile.worldVec);
    5.  
    6. // We'll render to the HUD canvas
    7. var canvas = GameObject.Find("HUDCanvas");
    8.  
    9. // Build a game object with the sprite
    10. var gameObject = new GameObject();
    11. gameObject.AddComponent<RectTransform>();
    12. gameObject.AddComponent<Image>();
    13. gameObject.GetComponent<Image>().sprite = drop.gameObject.GetComponent<SpriteRenderer>().sprite;
    14. gameObject.transform.position = screenPos;
    15. gameObject.transform.SetParent(canvas.transform);
    16. gameObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0.5f, 0);
    17.  
    18. var hotbar = GameObject.Find("Hotbar");
    19.  
    20. // Tween it
    21. LeanTween.move(gameObject, new Vector3(0, 0, 0), 0.25f).setEase( LeanTweenType.easeInQuad ).setOnComplete(() => {
    22.     Destroy(gameObject);
    23. });
    24.  
     
    Last edited: Jan 5, 2017
  2. PGJ

    PGJ

    Joined:
    Jan 21, 2014
    Posts:
    899
  3. viveleroi

    viveleroi

    Joined:
    Jan 2, 2017
    Posts:
    91
    Thanks, that worked. I was able to use RectTransformUtility.PixelAdjustPoint to convert the hotbar transform to a usable screen/pixel value.
     
  4. MaxMalts

    MaxMalts

    Joined:
    Feb 25, 2018
    Posts:
    6
    How did you do that? Can you post the code?
     
  5. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,212
    For finding the local coordinates of a child RectTransform in regards to the mouse I used this:

    Code (CSharp):
    1.             Vector3[] corners = new Vector3[4];
    2.             colorPickerRT.GetWorldCorners(corners);
    3.             Vector2 mousePos = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    4.             Vector2 localImagePos = (mousePos - (Vector2)corners[0]) / mainUIRT.localScale.x;
     
    sakshamarya and Diegodrax like this.
  6. edwardrowe

    edwardrowe

    Joined:
    Feb 11, 2014
    Posts:
    52
    I found this post while struggling to get a UI element to tween in local space (using its anchoredPosition) to the position of another (non-sibling) element.

    Here's the easiest way I found.

    First get the desired offset to the destination object in world space
    :

    var toDestinationInWorldSpace = destinationTransform.position - tweeningTransform.Position;


    Then translate the world space offset into the tweening object's local space using the tweening object's transform
    :

    var toDestinationInLocalSpace = tweeningTransform.InverseTransformVector(toDestinationWorld);


    Then you can tween or set your tweeningTransform.anchoredPosition to toDestinationInLocalSpace.

    See InverseTransformVector docs
     
  7. prashantmgk

    prashantmgk

    Joined:
    Sep 8, 2018
    Posts:
    2
    Thank you so much @edwardrowe .. i was stuck in that for 3 days.. really appreciate it
     
    edwardrowe likes this.
  8. sunwangshu

    sunwangshu

    Joined:
    Mar 2, 2017
    Posts:
    21
    Thanks, I finally used this set of stuff and it worked for me.

    I was trying to make the UI Button spawn at the position of a 2D
    SpriteRenderer
    . The script was attached to the GameObject with the
    SpriteRenderer


    Code (CSharp):
    1. public class AttachButton : MonoBehaviour
    2. {
    3.     [SerializeField] RectTransform buttonTransform;
    4.     [SerializeField] RectTransform canvasTransform;
    5.  
    6.     private void Awake()
    7.     {
    8.         Vector3 screenPos = Camera.main.WorldToScreenPoint(this.transform.position);
    9.         Vector2 screenPos2D = new Vector2(screenPos.x, screenPos.y);
    10.         Vector2 anchoredPos;
    11.         RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasTransform, screenPos2D, Camera.main, out anchoredPos);
    12.         buttonTransform.anchoredPosition = anchoredPos;
    13.     }
    14. }
     
    neoRiley and Pleija like this.
  9. giggioz

    giggioz

    Joined:
    May 11, 2017
    Posts:
    52
    It did not work for me, I had to adjust the position of that offset, like this

    Code (CSharp):
    1. public class Test : MonoBehaviour
    2. {
    3.     public RectTransform targetRect;
    4.     public RectTransform elementRect;
    5.  
    6.     public void GO(){
    7.         var toDestinationInWorldSpace = targetRect.position - elementRect.position;
    8.         var toDestinationInLocalSpace = elementRect.InverseTransformVector(toDestinationInWorldSpace);    
    9.         elementRect.anchoredPosition = elementRect.anchoredPosition + (Vector2)toDestinationInLocalSpace;
    10.     }
    11.  
    12. }
    But hey, thanks a lot!


    EDIT:

    using DoTween is even more elegant! Cheers

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using DG.Tweening;
    5.  
    6. public class MoveUIElementToUIElement : MonoBehaviour
    7. {
    8.     public RectTransform targetRect;
    9.     public RectTransform elementRect;
    10.  
    11.     public void GO()
    12.     {
    13.         var toDestinationInWorldSpace = targetRect.position - elementRect.position;
    14.         var toDestinationInLocalSpace = elementRect.InverseTransformVector(toDestinationInWorldSpace);
    15.         elementRect.DOAnchorPos(toDestinationInLocalSpace,1f).SetRelative(true);
    16.     }
    17. }
     
    Last edited: Oct 26, 2021
    emredesu likes this.