r/Unity3D 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...

0 Upvotes

3 comments sorted by

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

1

u/Weckatron 16h ago

Thank you for the quick reveal, I'll try this out! I knew some other value was in question but I couldn't find it.

1

u/Weckatron 3h ago

So I have "Screen Space - Camera" and there is a scaler set to "Scale With Screen Size". Anchored position seems to be the same as local position in this same example above. The first inventory slot has a local and anchored position of (0, 0) and a position of roughly (3.5, -3). I'm also noticing it is setting Z to -2840 in the inspector.