2
votes

The last few days I've been stuck with a headache of a problem in Unity.

Okay, I won't go into details with my game, but I've made a super-simple example which represents my issue.

I have a 2D scene these components: Basic scene

When the scene loads, and I tap the button this script executes:

Vector3 pos = transform.position;
pos.x -= 10;
transform.position = pos;

I have also tried this code:

transform.position = Camera.main.WorldToScreenPoint(new Vector3(0, 0, 0));

The problem is, that when I click the button, the x-pos of the object sets to -1536 which is not as expected. Picture shows the scene after the button has been clicked. Notice the Rect Transform values: After button click

So I did a little Googling and found out about ScreenToWorldPoint, WorldToScreenPoint etc but no of these conversions solves my problem.

I'm pretty sure I'm missing someting here, which probably is right in front of my, but I simply can't figure out what.

I hope someone can point me in the right direction.

Best regards.

6
Maybe try using localposition instead of position. Also, did both attempts in change transform.position give the exact same result, or?ChilliPenguin

6 Answers

2
votes

The issue is that you are using transform.position instead of rectTransform.anchoredPosition.

While it's true that UI elements are still GameObjects and do have the normal Transform component accessible in script, what you see in the editor is a representation of the RectTransform that is built on top. This is a special inspector window for UI elements, which use the anchored positioning system so you can specify how the edges line up with their parent elements.

When you set a GameObject's transform.position, you are providing a world space position specified in 3D scene units (meters by default). This is different from a local position relative to the canvas or parent UI element, specified in reference pixels (the reference pixel size is determined by the canvas "Reference Resolution" field).

A potential issue with your use of Camera.WorldToScreenPoint is that that function returns a position specified in pixels. Whereas, as mentioned before, setting the transform.position is specified in scene units (i.e. meters by default) and not relative to the parent UI element. The inspector, though, knows it's a UI element so instead of showing you that value, it is showing you the world position translated to the UI's local coordinates.

In other words, when you set the position to zero, you are getting the indices of whatever pixels happen to be over the scene's zero point in your main camera's view, and converting those pixel numbers to meters, and moving the element there. The editor is showing you a position in reference pixels (which are not necessarily screen pixels, check your canvas setting) relative to the object's parent UI element. To verify, try tilting your camera a bit and note that the value displayed will be different.

So again you would need to use rectTransform.anchoredPosition, and you would further need to ensure that the canvas resolution is the same as your screen resolution (or do the math to account for the difference). The way the object is anchored will also matter for what the rectTransform values refer to.

1
votes

Try using transform.localposition = new Vector3(0,0,0); as your button is a child of multiple game objects. You could also try using transform.TransformPoint, which should just convert localpos to worldpos.

1
votes

The issue is that your button is inside of another object. You want to be changing the local position. transform.localPosition -= new Vector3(10, 0, 0)

0
votes

Try these things because I did not understand what you were trying to do

Try using transform.deltaposition Go to the canvas and go then scale with screen size then! You can use transform.position = new Vector3(transform.position.x -10,transform.position.y, transform.positon.z)

And if this doesn't work transform.Translate(new Vector3(transform.deltaposition.x - 10,transform.deltaposition.y, transform.deltaposition.z);

0
votes

I have a better idea. Instead of changing the positions of the buttons, why not change the values that the buttons represent?

Moving Buttons

Remember that the buttons are GameObjects, and every gameobject has a position vector in its transform. So if your button is named ButtonA, then in your code you want to get a reference to that.

 GameObject buttonA = GameObject.Find("ButtonA");

//or you can assign the game object from the inspector

Once you have a reference to the button, you can proceed in moving it. So let's imagine that we want to move ButtonA 10 units left.

Vector3 pos = buttonA.transform.position;
 pos.X -= 10f;
 buttonA.transform.position = pos;
0
votes

As @Joseph has clearly explained, you have to make changes on your RectTransform for your UI components, instead of change Transform.

To achieve what you want, do it like this:

RectTransform rectTransform = this.GetComponent<RectTransform>();
Vector2 anchoredPos = rectTransform.anchoredPosition;
anchoredPos.x -= 10;
rectTransform.anchoredPosition = anchoredPos;

Just keep in mind that this 10 are not your 3D world space units (like meters or centimeters).