- Home /
Position + Vector3 doesn't return correct values
Hi! I'm currently working on a 2D menu game that needs to dynamically create menu items on a UI Canvas. As part of that, I'm using the following script:
menu_item_temp = Instantiate(menu_template, menu_template.transform.localPosition + new Vector3(0, -1, 0), menu_template.transform.rotation, List_Parent.transform);
I'd expect that code to instantiate a new copy of menu_template 1 unit below menu_template. Instead, it seems that it's creating it a few thousand units below the menu_template.
It was working before I changed my Canvas Scale mode from the default to 'Scale with Screen Size'. Playing with some numbers and removing variables, it seems like instead of Vector3(0, -1, 0) being interpreted as 1 unit down, it's being interpreted as 1/(canvas's y scale) unit down. I'm guessing it's using the Canvas's scale instead of the parent object's (which is a blank object with a (1,1,1) scale), but I'm not sure how or why that would happen.
I've tried multiplying the Vector3 y component with the canvas's scale to correct the issue, but placement is still a bit off depending on screen size (rounding issues I think?). Not sure what else to try :/
*Edit: For some more concrete numbers, I centered menu_template and all parents on (0,0,0). Reference resolution is 1920x1080 and preview window is 1024x768. UI scale for Y axis at this size is 0.006944444
With Vector3(0,0,0), menu_item_temp shows at (0,-286.56,0).
With Vector3(0,-1,0), menu_item_temp shows at (0,-430.56,0).
With Vector3(0,-2,0), menu_item_temp shows at (0,-574.56,0).
It seems that the correlation isn't as direct as I thought, but the numbers still change with the resolution of the preview window.
*Also, I realize that when I was initially working this out, I was using position instead of localPosition, which gives more consistent results. Still not what I'm looking for, but that's where my "1/(canvas's y scale)" came from.
Answer by Tobychappell · May 26, 2018 at 11:15 PM
In your code you are moving something by setting the transform.position, this is world coordinates, the UI space seems to be different Matrix or something so this movement needs to be translated. After poking around i found transform.TransformVector. I'm not hot on UI and stuff like this but i think below code should help.
Updated code once i found a reliable solution: it isn't exact due to rounding errors but it scales very well and is like 0.00001 off.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MyComponent : MonoBehaviour
{
public GameObject List_Parent;
public GameObject menu_template;
public Vector3 offset;
private void Awake()
{
GameObject menu_item_temp = Instantiate(menu_template, Vector3.zero, Quaternion.identity, List_Parent.transform);
menu_item_temp.transform.position = List_Parent.transform.position;
menu_item_temp.transform.position += menu_item_temp.transform.TransformVector(offset);
}
}
regarding rounding errors if they are not wanted, you could get the position, then round x and y to nearest integer then apply back. Thats if your going to be moving it in whole numbers.