Luxel Operation | DevBlog

Development Blog for Luxel Operation's upcoming games.

Earlier today I had a situation where I wanted to be able to place an element outside of the users screen while using a UIAnchor set to Center.
The reason for this was that the element needed to line up with a duplicate element in the center of the screen without overlapping. The two elements in this example are two halves of a full screen overlay (a “panel”) designed to hide the scene for menu transitions.

the_goal

The easiest method to get the two UI panels to get to the center and line up pixel perfect is to set the Pivot point on the left panel to be on the right side, and on the right panel do the opposite, setting the pivot to be the left center. This meant that when the localPosition of both panels was set to 0,0,0 they would line up perfectly in the middle of the screen without overlapping and it’d work on all resolutions/aspect ratios. (A UI Stretch component was added that set their Relative Size’s X to .5, so they each take up half of the width. The UI Root in this case is set to FixedSize)

Now came other half of the equation: Ensuring that each of these panels would start off screen and non-visible to the player so they could smoothly close without starting halfway onscreen, etc. A simple bit of math tells us that if we take Unity’s Screen.width and divide that by two then we could simply set the localPosition of each panel to be that far and they’d show up off screen. However, upon testing this I noticed a problem: If the code was run on anything but the ‘native’ resolution (1280×800 in this case), the panels would either show up too far off screen, or still be onscreen!

whats_happening

The reason for this is that when NGUI uses the FixedSize and it scales everything up/down from the 800 pixel height, it also impacts the horizontal positioning of elements. Why this specifically happens is unclear, but the fix is easy enough.

Instead of:

int panelOffset = Screen.width/2;
LeftPanel.transform.localPosition = new Vector3(-panelOffset, 0, 0);
RightPanel.transform.localPosition = new Vector3(panelOffset, 0, 0);

We use this neat little function, UIRoot.GetPixelSizeAdjustment. While the docs are unfortunately fairly vague, it’s pretty simple to use in practice:

int paneloffset = Mathf.FloorToInt(UIRoot.GetPixelSizeAdjustment(LeftPanel)*(Screen.width/2f))+1;
LeftPanel.transform.localPosition = new Vector3(-paneloffset, 0, 0);
RightPanel.transform.localPosition = new Vector3(paneloffset, 0, 0);

The reason for the Mathf.FloorToInt(…)+1 is to ensure that the elements definitely stay off screen. Due to floating point calculations the panels will often fall on a half or third pixel on the inside of the screen. By flooring it and adding one we ensure that we stay on a whole pixel and we stay off screen.

Tada!

Write a Comment

You must be logged in to post a comment.