Search Unity

Canvas Scaler and moving 2D items with touch

Discussion in 'UGUI & TextMesh Pro' started by Rosenumber14, Feb 6, 2015.

  1. Rosenumber14

    Rosenumber14

    Joined:
    Feb 5, 2015
    Posts:
    5
    Hello,
    I am developing a game and built my own infinite scroller that would lock onto a touch and follow the user's finger. It worked great until we added a canvas scaler to help scale some of our difficult UI elements for all devices. Here are the settings for the Canvas Scaler:

    UI Scale Mode: Scale With Screen Size
    Reference Resolution: x: 750 y:1334
    Screen Match Mode: Match width Or height
    Match: 0.5
    Reference pixels per unit: 100

    What i'm struggling with is trying to get an item that is within the canvas to follow your finger with every screen size. I have a panel inside the canvas that detects your touch using 'OnDrag' and i am setting the item's position inside the panel to eventdata.position. On the IPhone tall it seems to move slower then my finger, yet it works great on the IPhone5. Here is a little snippet of my code:

    public void OnDrag(PointerEventData eventData)
    {
    _item.transform.position = eventData.position;
    }

    This bug can be seen in the editor and on the phone. Please help!
     
  2. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    I've seen this a bit. There does appear to be a certain amount of lag between user / pointer input and Canvas Drawing.
    Might be worth logging with an example project
     
  3. Rosenumber14

    Rosenumber14

    Joined:
    Feb 5, 2015
    Posts:
    5
    Thanks for the response. Without the Canvas Scaler though, it works great, there does not seem to be any lagging and the app seems to be fully responsive. In my editor I can change the preset to the different phone sizes and depending on the size it scrolls faster or slower then my finger or perfectly if the phone is the same size as the Canvas Scaler's Reference Resolution: I think it has to do with the scaling of the UI that the canvas scaler does on 'Scale With Screen Size' mode. Any other ideas?
     
  4. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,689
    Interesting, I've not seen any cases where the Canvas Scaler would cause performance issues.
    Any idea @phil-Unity @Adam Buckner ?
     
  5. Rosenumber14

    Rosenumber14

    Joined:
    Feb 5, 2015
    Posts:
    5
    Here is an example project if this helps. If its not already, change to IOS in your build settings and set the screen size to iPhone Tall. I am currently in Unity 4.6.1 to see it just click on the button to begin dragging and drag it up and down you will see your mouse pass it up because its moving slower. Then try iphone 5 and you can see it move with your mouse. Maybe i need to compensate for something?
     

    Attached Files:

    Last edited: Feb 6, 2015
  6. rakkarage

    rakkarage

    Joined:
    Feb 3, 2014
    Posts:
    683
    Code (CSharp):
    1. _scaler = GetComponentInParent<CanvasScaler>();
    2. ...
    3. if (_scaler != null)
    4.     Drag(e.delta.x * _scaler.referenceResolution.x / Screen.width);
    5. else
    6.     Drag(e.delta.x);
     
  7. Rosenumber14

    Rosenumber14

    Joined:
    Feb 5, 2015
    Posts:
    5
    Hi, Thank you soo much rakkarage!! It works great!
     
    rakkarage likes this.
  8. BoaNeo

    BoaNeo

    Joined:
    Feb 21, 2013
    Posts:
    56
    The above is not entirely correct - it assumes that the reference resolution is matched to the actual screen by linear scaling in both directions which, depending on the MatchMode and Match width/height slider, may not be true.

    If you wish to avoid the headache of figuring that out, Unity has already done if for you in the Canvas transforms' "localScale" property (What I don't understand is why Unity doesn't do this before sending the event in the first place but it's just one of those things, I guess...)

    float dx = event.delta.x/_scaler.transform.localScale.x;
    float dy = event.delta.y/_scaler.transform.localScale.y;
     
    rakkarage and Harinezumi like this.
  9. Bezzy

    Bezzy

    Joined:
    Apr 1, 2009
    Posts:
    75
    I found that in some cases, using localScale wasn't working, and frustratingly the problem only turned up on the target platform.

    Code (CSharp):
    1.  
    2. CanvasScaler _canvasScaler;
    3. ...
    4. void Awake()
    5. {
    6. _canvasScaler = GetComponent<CanvasScaler>() ?? GetComponentInParent<CanvasScaler>();//anyone know if ?? is redundant here?
    7. }
    8. ...
    9. public Vector3 UnscaleEventDelta(Vector3 vec)
    10.     {
    11.         Vector2 referenceResolution = _canvasScaler.referenceResolution;
    12.         Vector2 currentResolution = new Vector2(Screen.width, Screen.height);
    13.  
    14.         float widthRatio = currentResolution.x / referenceResolution.x;
    15.         float heightRatio = currentResolution.y / referenceResolution.y;
    16.         float ratio = Mathf.Lerp(widthRatio, heightRatio, _CanvasScaler.matchWidthOrHeight);
    17.  
    18.         return vec /ratio;
    19.     }
    This code takes into account the "Match" slider as well.
     
  10. Vatio

    Vatio

    Joined:
    Sep 26, 2012
    Posts:
    11
  11. Jinxology

    Jinxology

    Joined:
    Jul 13, 2013
    Posts:
    95
    Bumping for Vatio's response above. That also worked for me and was the easiest solution I found by far
     
  12. eexxoo

    eexxoo

    Joined:
    Apr 6, 2013
    Posts:
    7
    The UnscaleEventDelta(..) method mainly works but it doesn't work properly when using a Canvas Scaler set to Match Width Or Height = 0.5 (slider in the middle) while having a small Screen.width and a big Screen.height. Any idea why the calculated mouse position is slightly off? I am trying to create a selection area using a blank image so there's no element to click to use PointerEventData.
     
  13. torfune420

    torfune420

    Joined:
    Feb 10, 2020
    Posts:
    1
    Big thanks for this! :)