Search Unity

Touch input woes: simple swipe to scroll gesture (iOS + Android)

Discussion in 'Scripting' started by reinfeldx, Oct 10, 2015.

  1. reinfeldx

    reinfeldx

    Joined:
    Nov 23, 2013
    Posts:
    164
    Goal: Swipe to control a 2D sprite along the X axis in world space. The feel should be similar to swiping to scroll through a list or article on any smartphone. In other words, I'm trying to implement proportional dragging, then inertia upon release of the touch. For the dragging, think 1:1 movement between touch and sprite, though I need the flexibility to change this proportion.

    Proposed pseudocode:

    // If there is a touch and its position changes
    // Know (or find) how much the position has changed in touch coordinates
    // Convert this change into world space terms
    // Apply the change to the GameObject​
    // If this touch ends
    // Know (or find) the speed at which the touch was moving in touch coordinates
    // Convert this speed into world space terms
    // Apply the speed to the GameObject​

    If someone has a solution for this, stop reading and let me know, but I haven't found a robust-enough implementation because of the following...

    I've been trying to track touches using various mixes of:
    • Update ()
      • if (touch.phase == TouchPhase.Moved) and similar TouchPhase statements
      • touch.position and changes in this value between Update () frames
    • touch.deltaPosition and touch.deltaTime, which are refreshed on their own clock
    Issue — The rate at which touch inputs are recorded and Update () is called is different (compare touch.deltaTime and Time.deltaTime). The following are examples that might not be real-world scenarios, but illustrate the point:
    • If touches are updated at 60 fps and Update runs at lower than 30 fps, working with touch.delta values within Update () will result in missed touch.delta refreshes
    • If Update () runs at 60 fps and and touches refresh at lower than 30 fps, Update () will capture the same touch.delta values twice or more
    The point here is that the mismatched intervals between touch tracking and calls to Update () make working with touch inside of Update () problematic. The way I see it, at best you're losing accuracy of touches, and at worst you're introducing some inconsistencies that could result in some noticeable bugs. Unfortunately in my case, accuracy of touches is paramount, as it is directly tied to the main gameplay mechanic.

    Back in the real world, I've been able to come up with good implementations on two iPhone 5 devices, but my tests on two different Android phones (Moto E and Moto X) resulted in less responsive touches. In other words, the swipes were not translating to 1:1 moves of the GameObject. I think this is due to the mismatched timing I've described.

    Now might be a good time to mention my method of converting touch positions into world space.
    Code (CSharp):
    1. worldTouchDeltaPosition = Camera.main.ScreenToWorldPoint(new Vector3
    2.     (touch.deltaPosition.x, touch.deltaPosition.y, Camera.main.transform.position.z))
    3.     - Camera.main.ScreenToWorldPoint(Vector3.zero);
    Maybe this is the problem on Android, though I don't think so (the Moto E has lower pixel density than the iPhone 5, while Moto X is about the same). Anyway, I'm pretty sure ScreenToWorldPoint should control for changes in pixel density.

    I'm interested in understanding better what is going on here, but most importantly finding a solution that works across iOS and Android. Hopefully someone can help me out and/or walk me back from my insanity here. :confused:
     
    Last edited: Oct 11, 2015
  2. reinfeldx

    reinfeldx

    Joined:
    Nov 23, 2013
    Posts:
    164
    Any ideas? I know it's kinda complicated but I could really use some feedback here. :/
     
  3. reinfeldx

    reinfeldx

    Joined:
    Nov 23, 2013
    Posts:
    164