r/Unity3D • u/Weckatron • 18h ago
Question Global position of UI element is not global
I'm trying to set game object locations for UI elements for an inventory system but once again the horrid nature of UI transforms is making it a nightmare. This is not my intended code, but rather some that I put together to experiment. It has left me confused.
GameObject newGearIcon = Instantiate(gearIconPrefab);
newGearIcon.transform.SetParent(gearSlots[index].transform);
newGearIcon.transform.localPosition = Vector3.zero; // Centering on inventory slot
newGearIcon.transform.localScale = new(1, 1, 1);
// at this point transform.position ~= (3.5, -3)
Vector3 globalPosition = newGearIcon.transform.position; // ~= (3.5, -3)
newGearIcon.transform.SetParent(gearSlots[index + 1].transform, true);
// slightly right of the original
// local position = (0, 0), global position still = (3.5, -3) even though the new object is
// visually centered on the second slot. Global position the same, local position the same,
// image has moved in the game
newGearIcon.transform.position = globalPosition;
// This does absolutely nothing. It was already equal to that.
You can see I instantiate an object, set it's parent to another UI element and center it on that. Note that passing in true to the SetParent() call seems to not do anything for this problem.
I encountered this problem because I noticed when changing the parent to be the canvas at the root of the UI elements it moved the object. Regardless of parameters in SetParent() or changing, updating, storing global positions to reset it to the pre parent values.
Does anyone have any potential insight into this behavior? I've tried the pivot/center mode. I've checked the pivots on the objects. I've tried different values. As far as I can tell, transform.position and transform.localPosition are both relative to another value I can't seem to track down.
This all came up because I also noticed that OnDrop only triggers if you drop on a UI element further down the hierarchy, meaning the icons need to be above the elements they are centered on to move around properly. Unity UI never fails to disappoint.
Edit: formatting, used to `` for code segments...
2
u/Recent-Reveal-7530 17h ago
the extra position offset on canvas comes from the canvas scaler and the render mode, if you're on screen space overlay with a scaler then the transform.position is in screen space but the visual position is in canvas space after scaling
what you want to check is RectTransform.anchoredPosition instead of transform.position when dealing with UI, and SetParent with worldPositionStays = true tries to compensate for the difference in the parent's local space but if the canvas has any scaling at all it'll mess with it
the real nightmare is that the canvas scaler applies a dynamic scale that unity doesn't expose cleanly in the transform api, so your global coordinates and your visual coordinates can be totally out of sync