0
\$\begingroup\$

In my Unity scene, I have a couple of spriteRenderers and a UnityEngine.UI.Button called thisButton. The spriteRenderers are spread horizontally across my scene. I want to change the button width to span from the leftmost spriteRenderer to the rightmost spriteRenderer.

To do this, I have subtracted the x-Coordinate of the rightmost spriteRenderer (fRightEndingPosition) from the x-Coordinate of the leftmost spriteRenderer (fLeftStartingPosition).

float fLeftStartingPosition = leftmostSpriteRenderer.transform.position.x;
float fRightEndingPosition = rightmostSpriteRenderer.transform.position.x;
float fButtonTargetWidth = fRightEndingPosition - fLeftStartingPosition;

Then, I try to set the width of thisButton to the value of fButtonTargetWidth by doing

RectTransform buttonSize = thisButton.GetComponent<RectTransform>();
buttonSize.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, fButtonTargetWidth);

However, when I try to use this as the width of my button, the result is not correct. I am pretty sure this has something to do with different types of coordinates being used for the spriteRenderers and the button (world, screen, viewport, etc.), but I haven't been able to figure this out on my own.

In one specific example fLeftStartingPosition is -1.1, and fRightEndingPosition is 1.1. In my scene, a button that spans this distance has a width of roundabout 40 on its RectTransform. So clearly, setting the width of this RectTransform (buttonSize) to fButtonTargetWidth (2.2) in code results in a button that is way to narrow. In fact, after setting it's width to 2.2, it is not visible at all.

How do I transform this distance of 2.2 to the desired width of roundabout 40, in a way that this distance would be transformed correctly, no matter what the actual value of fButtonTargetWidth is?

\$\endgroup\$
1
\$\begingroup\$

Your solution might work with a world-space canvas, but I don't recommend using world-space canvases for most situations because it's difficult to make them adapt to different screen aspect ratios/resolutions.

If you're using a Screen Space canvas, you need to convert the world coordinates of the sprite renderers into screen space, then convert that into canvas space.

This solution works for cameras set to "Screen Space - Overlay" or "Screen Space - Canvas":

//This solution does NOT work for world-space canvases!
Assert.IsFalse(canvas.renderMode == RenderMode.WorldSpace);
Canvas canvas = thisButton.GetComponentInParent<Canvas>();
Vector3 leftScreen = Camera.main.WorldToScreenPoint(leftmostSpriteRenderer.transform.position);
Vector3 rightScreen = Camera.main.WorldToScreenPoint(rightmostSpriteRenderer.transform.position);

RectTransform buttonRT = thisButton.GetComponent<RectTransform>();
var sizeDelta = buttonRT.sizeDelta;
sizeDelta.x = (rightScreen.x - leftScreen.x) / canvas.scaleFactor;
buttonRT.sizeDelta = sizeDelta;

What we do here is convert the positions of the two sprite renderers into screen coordinates (which are in pixels), then convert the screen coordinates into canvas dimensions by dividing by the canvas scale factor (since the canvas scale factor is a ratio of canvas coordinates to screen coordinates).

\$\endgroup\$
  • \$\begingroup\$ Thank you Kevin, this works! Thanks for the explanation as well! \$\endgroup\$ – Chris Sep 3 '20 at 22:37
  • \$\begingroup\$ @Chris Great, glad to help! \$\endgroup\$ – Kevin Sep 4 '20 at 16:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.