Search Unity

Setting 'Pos Z' in RectTransform via scripting

Discussion in 'UGUI & TextMesh Pro' started by TimBur, Sep 24, 2014.

  1. TimBur

    TimBur

    Joined:
    Jan 17, 2013
    Posts:
    35
    Right now, I don't know how to do this. There may be a way to do it, but at the least, it's non-intuitive. I suggest the current uGUI API could be improved by making it easier to set this value.

    In the inspector panel for a Rect Transform, the top line shows three numbers: 'Pos X' / 'Left', 'Pos Y' / 'Top', and 'Pos Z'. You can set the first two using RectTransform.anchoredPosition. However, anchoredPosition is a Vector2 rather than a Vector3. Given that Pos Z does (sometimes) impact the effect/location of a RectTransform, I think that anchoredPosition should be a Vector3, and that the third component should map to Pos Z.

    Thoughts?
     
    lasdoo5 likes this.
  2. JAKJ

    JAKJ

    Joined:
    Aug 17, 2014
    Posts:
    185
    The z will be in Transform, not RectTransform.
     
  3. TimBur

    TimBur

    Joined:
    Jan 17, 2013
    Posts:
    35
    I've just given that a try, and you're right, you can set Pos Z via transform.position, and transform.localPosition, but it's very awkward. Have you tried this yourself?

    For example, this:
    Code (CSharp):
    1. newbutton.GetComponent<RectTransform>().localPosition = new Vector3(1,2,3);
    results in a RectTransform like this:
    Capture.JPG
    Notice that Pos Z has the desired value, while Pos X and Pos Y are essentially gibberish. From this, I would guess that localPosition x/y are being run through some sort of transform before being assigned/displayed as Pos X and Pos Y. As that transform is very nonintuitive, I don't think you'd ever want to set Pos X or Pos Y using localPosition.

    This means that if you want to set Pos X/Y/Z, you'd need to set Pos X and Y via anchoredPosition, and then set Pos Z in a careful way so as not to alter Pos X/Y. Something like this:
    Code (CSharp):
    1. newbutton.GetComponent<RectTransform>().anchoredPosition =
    2.      new Vector2(<value4PosX>, <value4Posy>;
    3. newbutton.GetComponent<RectTransform>().localPosition =
    4.      new Vector3(newbutton.GetComponent<RectTransform>().localPosition.x,
    5.                  newbutton.GetComponent<RectTransform>().localPosition.y,
    6.                  <value4PosZ>);
    which feels very awkward.

    So, I still think it would be useful to change anchoredPosition to a Vector3, and map the third component onto Z. You could then set all three Pos's in one statement.

    Again, thoughts? Is there some easier way to do this?
     
    MrKsi, Lohaz and Devil_Inside like this.
  4. JAKJ

    JAKJ

    Joined:
    Aug 17, 2014
    Posts:
    185
    Why is it awkward? A canvas is a transformational space, a relative space if you will. Transform is its world position: RectTransform is its position inside that space. What you're trying to do (if I understand what you're trying to do) is silly: If you're trying to transform something in absolute coordinates in the world, you transform the canvas it's on. These components *cannot exist* outside a canvas, so it makes no sense for them to be positioned as if the canvas isn't there.

    If you want to move a canvas relative to the world, use its transform. If you want to move a component relative to the canvas, use its recttransform. Z is still available in the component's transform for the occasional sorting need.
     
  5. TimBur

    TimBur

    Joined:
    Jan 17, 2013
    Posts:
    35
    You're right, my goal is to move a component relative to the canvas, and I'd like to use RectTransform to do so. The z-coordinate is a legitimate and important part of that relative position, but it's harder to access than x and y. It appears that I can only directly access the z-coord of a component by using position. As position uses world-coordinates rather than pixel coordinates, it's awkward (even silly) to use 'position' to set the position of a component within a canvas, but that's what you have to do. Given that we're still in beta, and Unity aims to be relatively user-friendly, I think it's useful to consider ways to make it easier to access the z-coord, ways to access this number without having to use world coordinates.

    I can give you a use case, the situation that led me to ask this question:

    I created a Canvas, set the render mode to 'Screen Space - Camera', and positioned the Canvas and the Camera as needed. I then have a set of context-sensitive buttons that I wanted to place in the canvas. I made a button prefab, then wrote a script to create the actual buttons. I called Instantiate(buttonprefab), and set Canvas as the parent transform for the new button. The new button was initially positioned at some odd and arbitrary coordinates, and setting the Canvas as parent put the relative coordinates (Pos X, Pos Y, Pos Z) to odd values. I easily set Pos X and Pos Y as needed, using anchoredPosition to set the location relative to the Canvas. However, it was hard to set Pos Z, as I could only directly affect Pos Z with position/localPosition.

    I've since changed my call to Instantiate to reference the position and rotation of the button prefab as Instantiate(buttonprefab, buttonprefab.transform.position, buttonprefab.transform.rotation). That creates the new object at the desired z-coord. Still, in a good API, there are multiple ways of getting to the same end, so that users can choose the method appropriate to their circumstances. Thus, I think it would be useful to have a better way to directly access the z-coord of a RectTransform.
     
  6. JAKJ

    JAKJ

    Joined:
    Aug 17, 2014
    Posts:
    185
    I don't completely understand your use-case, but it sounds like you're having problems with it screwing up your positioning when setting the parent of an instantiated prefab. If you use childObject.transform.SetParent(parentObject.transform,false) it will not do this.
     
  7. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    The intended way for now is to use anchoredPosition for X and Y and localPosition.z for the Z part.

    We've exposed a new property, anchoredPosition3D, which can be used to do it all at once. It' come in a future beta.
     
  8. TimBur

    TimBur

    Joined:
    Jan 17, 2013
    Posts:
    35
    The parenting isn't the problem. The parenting was a part of my work flow, but the source of the problem was my use of Instantiate. When I use the one-parameter version of Instantiate, the version without the position argument, then the new object shows up at a semi-random 3D position, and I need to be able to change all 3 coordinates in order to get the object correctly positioned within my canvas.
     
  9. TimBur

    TimBur

    Joined:
    Jan 17, 2013
    Posts:
    35
    That's great! Just what I was hoping for.
     
  10. samra2494

    samra2494

    Joined:
    Nov 23, 2015
    Posts:
    21
    It works for me

    private void SetPosition(RectTransform go)
    {
    go.localPosition = new Vector3(0,0,0);
    go.localRotation = Quaternion.identity;
    go.localScale = new Vector3(1,1,1);
    }
     
    Kureshik likes this.
  11. vex_virtual_exhibitions_ltd

    vex_virtual_exhibitions_ltd

    Joined:
    Dec 9, 2015
    Posts:
    2
    newButton.GetComponent<RectTransform>().anchoredPosition3D = new Vector3 (newButton.GetComponent<RectTransform>().anchoredPosition3D.x,newButton.GetComponent<RectTransform>().anchoredPosition3D.y,0); this allows you to keep the current X and Y as its reusing them values and just setting the Z this worked for me
     
    Luferau and First_Space_man like this.