Search code examples
c#user-interfaceunity-game-enginemouseunity3d-gui

GUI Canvas scaling problems using localPosition


So I'm following a tutorial online and am 99.9% sure I have not made an error and it is perhaps something to do with my trying to implement his ideas in to an already established project with (perhaps) different concerning factors.

The general idea from the math is that my SlotScriptwhich implements IDragHandler, OnDrag-

public void OnDrag(PointerEventData data)
{
    if (inventory.Items[slotNumber].itemName != null)
    {
        inventory.ShowDraggedItem(inventory.Items[slotNumber]);
    }
}

executes a method in my inventory which simply assigns bool draggingItem as true and changes it's sprite along with making it active.

Now my actual update code for returning the dragged item's position isn't returning it's expected value:

void Update()
{
    if (draggingItem)
    {
        Vector3 position = (Input.mousePosition - (GameObject.FindObjectOfType<Canvas>().GetComponent<RectTransform>().localPosition));
        draggedItem.GetComponent<RectTransform>().localPosition = new Vector3(position.x + 15, position.y - 15, position.z);
    }
}

Here are some examples of what I get. When the mouse is in the center of the canvas I get the expected result:

enter image description here

If I drag the item outwards to any edge the value becomes distorted always returning less than the value should be, for example:

enter image description here

enter image description here

Other information:

Screen space is set to overlay. Native resolution is at 1920x1080. When tested on a smaller resolution size the problem is worsened (the offset is proportionally larger). Once the onDrag event occurs the mousePosition updates correctly and the Canvas localPosition stays exactly the same (expected behaviour?)

I hope I made this clear enough.


Solution

  • Well I was very surprised to see no one had an answer to this!

    Regardless, it turns out after about 2 hours (probably more over the extended period) of playing around with it I noticed that although (stated very clearly) the canvas scales based on screen resolution it does not then scale the return value of localPosition, this you have to do yourself.

    I'm tired so hopefully that made sense.

    All you need to know if you've also encountered this problem is that once you divide the expected position of the mousePointer on your canvas by any value (x, y, z) of the Vector3 localScale in the Canvas RectTransform component it returns the scaled position (because of cause dividing by less than 1 increases your value).

    Code to solve featured below:

    if (draggingItem)
        {
            Vector3 localScale = GameObject.FindObjectOfType<Canvas>().GetComponent<RectTransform>().localScale;
            Vector3 position = (Input.mousePosition - (GameObject.FindObjectOfType<Canvas>().GetComponent<RectTransform>().localPosition));
            Vector3 positionDivided = new Vector3(position.x, position.y, position.z) / localScale.x;
    
            draggedItem.GetComponent<RectTransform>().localPosition = new Vector3(positionDivided.x + 15, positionDivided.y - 15, positionDivided.z);
        }