- Home /
Converting into a parent RectTransform's Coordinates (and back again)
I'm having a bit of a problem converting between coordinate systems at different levels of UI hierarchy and I was wondering if you could help me.
I'm trying to write a technology tree and I've got it working providing the anchors are arranged very specifically and the elements that make up the technology tree are all children of the tree container.
I'd like it to be a bit more flexible than that and at the heart of it seems to be a problem writing a generic function that will convert from child to parent UI elements and back again.
One part of it seems to be the way anchors work. As far as I understand it, I think anchors are the points in the parent object's space that are where the anchorPosition vector works from, with differences for strech anchors. How that fits all together, I'm not too sure.
These are the functions I've got working for one layer. Many thanks for any help.
public static Vector2 TransformMyToAncestorSpace( GameObject me, GameObject ancestor, Vector2 point )
{
Vector2 ret = point;
GameObject GO=me, parentGO=Hierarchy.Parent(GO);
RectTransform RT, parentRT;
while (GO != ancestor && parentGO != null) {
Debug.Log ("TMtAS: Debug: ");
RT = GO.GetComponent<RectTransform> ();
parentRT = parentGO.GetComponent<RectTransform> ();
//Vector2 pos;
if (parentRT.anchorMax == parentRT.anchorMin) {
ret = RT.anchoredPosition + ret + new Vector2 (parentRT.sizeDelta.x * parentRT.anchorMin.x, parentRT.sizeDelta.y * parentRT.anchorMin.y);
} else {
ret = RT.anchoredPosition + ret + parentRT.pivot;
}
//ret = ret + RT.anchoredPosition;
GO = Hierarchy.Parent (GO);
parentGO = Hierarchy.Parent (GO);
}
if (GO == ancestor)
return ret;
else
return default(Vector2);
}
public static Vector2 TransformAncestorToMySpace( GameObject ancestor, GameObject me, Vector2 point )
{
Vector2 ret = point;
GameObject GO=me, parentGO=Hierarchy.Parent(GO);
RectTransform RT, parentRT;
while (GO != ancestor && parentGO != null) {
Debug.Log ("TAtMS: Debug");
RT = GO.GetComponent<RectTransform> ();
parentRT = parentGO.GetComponent<RectTransform> ();
if (parentRT.anchorMax == parentRT.anchorMin) {
ret = -RT.anchoredPosition + ret - new Vector2 (parentRT.sizeDelta.x * parentRT.anchorMin.x, parentRT.sizeDelta.y * parentRT.anchorMin.y);
} else {
ret = -RT.anchoredPosition + ret - parentRT.pivot;
}
//ret = ret - RT.anchoredPosition;
GO = Hierarchy.Parent (GO);
}
if (GO == ancestor)
return ret;
else
return default(Vector2);
}
Answer by HM2D · May 07, 2021 at 11:22 AM
I've made a script that reverse engineers the unity's rect transforms when you're changing how they are parented. Only handles th normal pivot presets. Hope it helps for anyone who had a go at this. P.S: m_MidAnchor = Vector2(0.5,0.5)
private Rect TransformToAncestorSpace(RectTransform selectable, RectTransform ancestor)
{
Vector2 position = selectable.anchoredPosition;
string debugString = selectable.name +"\n";
Vector2 currentScale = selectable.localScale;
RectTransform parentRect = selectable.parent.GetComponent<RectTransform>();
//Centering the anchor on the selectable
position = CenterAnchor(selectable, parentRect, position);
if(selectable.anchoredPosition != position)
debugString += " Centering ->" + position;
while (parentRect != ancestor)
{
debugString += " parent->" + parentRect.name;
debugString += " position:" + position;
currentScale *= parentRect.localScale;
ScrollRect scroll = parentRect.GetComponent<ScrollRect>();
if (scroll)
{
m_ScrollableItem.Add(true);
if (m_ScrollRect == null)
{
m_ScrollRect = scroll;
RectTransform scrollRectTransform = scroll.GetComponent<RectTransform>();
m_ScrollRectTransform = new Rect(scrollRectTransform.anchoredPosition, scrollRectTransform.sizeDelta * new Vector2(1.2f, 1.2f));
}
}
else m_ScrollableItem.Add(false);
//non-stretched anchors
if (!(parentRect.anchorMin == Vector2.zero && parentRect.anchorMax == Vector2.one))
{
RectTransform GrandParentRect = parentRect.transform.parent.GetComponent<RectTransform>();
//find the non-stretched parent
while (GrandParentRect.anchorMin == Vector2.zero && GrandParentRect.anchorMax == Vector2.one)
GrandParentRect = GrandParentRect.transform.parent.GetComponent<RectTransform>();
debugString += " GP " + GrandParentRect.name;
Vector2 translatedPosition = parentRect.anchoredPosition;
Vector2 halfSize = m_MidAnchor * parentRect.sizeDelta * parentRect.localScale;
//Centering the pivot
if (parentRect.pivot.x != m_MidAnchor.x)
translatedPosition.x = parentRect.pivot.x < m_MidAnchor.x ? translatedPosition.x + halfSize.x : translatedPosition.x - halfSize.x;
if (parentRect.pivot.y != m_MidAnchor.y)
translatedPosition.y = parentRect.pivot.y < m_MidAnchor.y ? translatedPosition.y + halfSize.y : translatedPosition.y - halfSize.y;
//Centering the anchor position
Vector2 GPHalfSize = m_MidAnchor * GrandParentRect.sizeDelta * GrandParentRect.localScale;
if (parentRect.anchorMax.x != m_MidAnchor.x)
translatedPosition.x = parentRect.anchorMax.x < m_MidAnchor.x ? translatedPosition.x - GPHalfSize.x : translatedPosition.x + GPHalfSize.x;
if (parentRect.anchorMax.y != m_MidAnchor.y)
translatedPosition.y = parentRect.anchorMax.y < m_MidAnchor.y ? translatedPosition.y - GPHalfSize.y : translatedPosition.y + GPHalfSize.y;
position *= currentScale;
position += translatedPosition;
debugString += "+ PTP:" + translatedPosition;
debugString += "->" + position;
}
else
{
debugString += " Stretched";
position += parentRect.anchoredPosition;
}
parentRect = parentRect.transform.parent.GetComponent<RectTransform>();
debugString += "\n";
}
Rect theRect = new Rect(position, currentScale * selectable.sizeDelta);
Debug.Log(debugString + theRect);
return theRect;
}
Vector3 CenterAnchor(RectTransform selectable, RectTransform parentRect, Vector3 position)
{
if (selectable.anchorMax != m_MidAnchor)
{
Vector2 translatedAnchor = position;
RectTransform GrandParentRect = parentRect;
//find the non-stretched parent
while (GrandParentRect.anchorMin == Vector2.zero && GrandParentRect.anchorMax == Vector2.one)
GrandParentRect = GrandParentRect.transform.parent.GetComponent<RectTransform>();
Vector2 halfSize = m_MidAnchor * GrandParentRect.sizeDelta * GrandParentRect.localScale;
if (selectable.anchorMax.x != m_MidAnchor.x)
translatedAnchor.x = selectable.anchorMax.x < m_MidAnchor.x ? translatedAnchor.x - halfSize.x : translatedAnchor.x + halfSize.x;
if (selectable.anchorMax.y != m_MidAnchor.y)
translatedAnchor.y = selectable.anchorMax.y < m_MidAnchor.y ? translatedAnchor.y - halfSize.y : translatedAnchor.y + halfSize.y;
position = translatedAnchor;
}
return position;
}
Update: Now handles streched pivots and scrollable items inside scrollrect
Your answer
Follow this Question
Related Questions
RectTransform Pivot Point in the new UI? 1 Answer
Force Unity UI element to refresh/update? 4 Answers
How to get a Rect from Image or RectTranform? 1 Answer
Change RectTransform pivot without changing position 0 Answers
this code doesnt work when the buttons anchor are not same(custom anchor) 0 Answers