Search Unity

Simple swipe and tap mobile input

Discussion in 'Scripting' started by MD_Reptile, Dec 26, 2015.

  1. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,585
    I couldn't find a decent working example of basic swipe and tap input using recent unity versions (as of this writing this works with 5.3 unity) so I went ahead and cobbled a simple snippet together that basically handles it. It isn't heavily battle tested and might not be perfect, but seems to work from the 5 minutes or so of testing I did. Original credit goes to Sujit Horakeri of "the game contriver".

    EDIT: Note - if you want 8 directional movement and mouse "touch simulation" check the later posts!

    Adapted from here:
    http://www.thegamecontriver.com/2014/08/unity3d-swipe-input-for-touch-screen.html

    Anyway here she be, ready to go in unity 5.3:

    Code (CSharp):
    1.     private Vector3 fp;   //First touch position
    2.     private Vector3 lp;   //Last touch position
    3.     private float dragDistance;  //minimum distance for a swipe to be registered
    4.  
    5.     void Start()
    6.     {
    7.         dragDistance = Screen.height * 15 / 100; //dragDistance is 15% height of the screen
    8.     }
    9.  
    10.     void Update()
    11.     {
    12.         if (Input.touchCount == 1) // user is touching the screen with a single touch
    13.         {
    14.             Touch touch = Input.GetTouch(0); // get the touch
    15.             if (touch.phase == TouchPhase.Began) //check for the first touch
    16.             {
    17.                 fp = touch.position;
    18.                 lp = touch.position;
    19.             }
    20.             else if (touch.phase == TouchPhase.Moved) // update the last position based on where they moved
    21.             {
    22.                 lp = touch.position;
    23.             }
    24.             else if (touch.phase == TouchPhase.Ended) //check if the finger is removed from the screen
    25.             {
    26.                 lp = touch.position;  //last touch position. Ommitted if you use list
    27.  
    28.                 //Check if drag distance is greater than 20% of the screen height
    29.                 if (Mathf.Abs(lp.x - fp.x) > dragDistance || Mathf.Abs(lp.y - fp.y) > dragDistance)
    30.                 {//It's a drag
    31.                  //check if the drag is vertical or horizontal
    32.                     if (Mathf.Abs(lp.x - fp.x) > Mathf.Abs(lp.y - fp.y))
    33.                     {   //If the horizontal movement is greater than the vertical movement...
    34.                         if ((lp.x > fp.x))  //If the movement was to the right)
    35.                         {   //Right swipe
    36.                             Debug.Log("Right Swipe");
    37.                         }
    38.                         else
    39.                         {   //Left swipe
    40.                             Debug.Log("Left Swipe");
    41.                         }
    42.                     }
    43.                     else
    44.                     {   //the vertical movement is greater than the horizontal movement
    45.                         if (lp.y > fp.y)  //If the movement was up
    46.                         {   //Up swipe
    47.                             Debug.Log("Up Swipe");
    48.                         }
    49.                         else
    50.                         {   //Down swipe
    51.                             Debug.Log("Down Swipe");
    52.                         }
    53.                     }
    54.                 }
    55.                 else
    56.                 {   //It's a tap as the drag distance is less than 20% of the screen height
    57.                     Debug.Log("Tap");
    58.                 }
    59.             }
    60.         }
    61.     }
     
    Last edited: Sep 18, 2016
    Draag, HunnyMalik, AhmedTayea and 7 others like this.
  2. MOSTY

    MOSTY

    Joined:
    Sep 6, 2013
    Posts:
    266
    prozario likes this.
  3. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,585
    While I did look into your product, I wasnt sure it would be right for me, so I ended up moving onto another publicly available script, which I found a sample somewhere here on the forum, that uses 8 directions of movement, allowing up-right, and all other diagonal directions. I'll post the code to that here for future reference when I get back to my dev machine.
     
    prozario likes this.
  4. meethi

    meethi

    Joined:
    Sep 12, 2016
    Posts:
    1
    Thank you so much!:)
     
    MD_Reptile likes this.
  5. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,585
    Hey totally forgot to ever share the 8 directional version! Sorry if anybody had been waiting on that!

    This version allows the mouse to emulate touches in the editor (great for debugging and rapid prototyping) and of course has 8 directions of "swipe detection" rather than only 4.

    Anyway I didn't write all of this, and instead found most of this in another topic ( http://forum.unity3d.com/threads/swipe-in-all-directions-touch-and-mouse.165416/ ), although there might be modifications here and there, it should help get you going in the right direction :p

    using UnityEngine;
    using System.Collections;

    public struct SwipeAction
    {
    public SwipeDirection direction;
    public Vector2 rawDirection;
    public Vector2 startPosition;
    public Vector2 endPosition;
    public float startTime;
    public float endTime;
    public float duration;
    public bool longPress;
    public float distance;
    public float longestDistance;

    public override string ToString()
    {
    return string.Format("[SwipeAction: {0}, From {1}, To {2}, Delta {3}, Time {4:0.00}s]", direction, rawDirection, startPosition, endPosition, duration);
    }
    }

    public enum SwipeDirection
    {
    None, // Basically means an invalid swipe
    Up,
    UpRight,
    Right,
    DownRight,
    Down,
    DownLeft,
    Left,
    UpLeft
    }

    /// <summary>
    /// Swipe manager.
    /// BASED ON: http://forum.unity3d.com/threads/swipe-in-all-directions-touch-and-mouse.165416/#post-1516893
    /// </summary>
    public class SwipeManager : MonoBehaviour
    {
    public System.Action<SwipeAction> onSwipe;
    public System.Action<SwipeAction> onLongPress;

    [Range(0f, 200f)]
    public float minSwipeLength = 100f;

    public float longPressDuration = 0.5f;

    Vector2 currentSwipe;
    SwipeAction currentSwipeAction = new SwipeAction();

    void Update()
    {
    DetectSwipe();
    }

    public void DetectSwipe()
    {
    var touches = InputHelper.GetTouches();
    if (touches.Count > 0)
    {
    Touch t = touches[0];

    if (t.phase == TouchPhase.Began)
    {
    ResetCurrentSwipeAction(t);
    }

    if (t.phase == TouchPhase.Moved || t.phase == TouchPhase.Stationary)
    {
    UpdateCurrentSwipeAction(t);
    if (!currentSwipeAction.longPress && currentSwipeAction.duration > longPressDuration && currentSwipeAction.longestDistance < minSwipeLength)
    {
    currentSwipeAction.direction = SwipeDirection.None; // Invalidate current swipe action
    currentSwipeAction.longPress = true;
    if (onLongPress != null)
    {
    onLongPress(currentSwipeAction); // Fire event
    }
    return;
    }
    }

    if (t.phase == TouchPhase.Ended)
    {
    UpdateCurrentSwipeAction(t);

    // Make sure it was a legit swipe, not a tap, or long press
    if (currentSwipeAction.distance < minSwipeLength || currentSwipeAction.longPress) // Didnt swipe enough or this is a long press
    {
    currentSwipeAction.direction = SwipeDirection.None; // Invalidate current swipe action
    return;
    }

    if (onSwipe != null)
    {
    onSwipe(currentSwipeAction); // Fire event
    }
    }
    }
    }

    void ResetCurrentSwipeAction(Touch t)
    {
    currentSwipeAction.duration = 0f;
    currentSwipeAction.distance = 0f;
    currentSwipeAction.longestDistance = 0f;
    currentSwipeAction.longPress = false;
    currentSwipeAction.startPosition = new Vector2(t.position.x, t.position.y);
    currentSwipeAction.startTime = Time.time;
    currentSwipeAction.endPosition = currentSwipeAction.startPosition;
    currentSwipeAction.endTime = currentSwipeAction.startTime;
    }

    void UpdateCurrentSwipeAction(Touch t)
    {
    currentSwipeAction.endPosition = new Vector2(t.position.x, t.position.y);
    currentSwipeAction.endTime = Time.time;
    currentSwipeAction.duration = currentSwipeAction.endTime - currentSwipeAction.startTime;
    currentSwipe = currentSwipeAction.endPosition - currentSwipeAction.startPosition;
    currentSwipeAction.rawDirection = currentSwipe;
    currentSwipeAction.direction = GetSwipeDirection(currentSwipe);
    currentSwipeAction.distance = Vector2.Distance(currentSwipeAction.startPosition, currentSwipeAction.endPosition);
    if (currentSwipeAction.distance > currentSwipeAction.longestDistance) // If new distance is longer than previously longest
    {
    currentSwipeAction.longestDistance = currentSwipeAction.distance; // Update longest distance
    }
    }

    SwipeDirection GetSwipeDirection(Vector2 direction)
    {
    var angle = Vector2.Angle(Vector2.up, direction.normalized); // Degrees
    var swipeDirection = SwipeDirection.None;

    if (direction.x > 0) // Right
    {
    if (angle < 22.5f) // 0.0 - 22.5
    {
    swipeDirection = SwipeDirection.Up;
    }
    else if (angle < 67.5f) // 22.5 - 67.5
    {
    swipeDirection = SwipeDirection.UpRight;
    }
    else if (angle < 112.5f) // 67.5 - 112.5
    {
    swipeDirection = SwipeDirection.Right;
    }
    else if (angle < 157.5f) // 112.5 - 157.5
    {
    swipeDirection = SwipeDirection.DownRight;
    }
    else if (angle < 180.0f) // 157.5 - 180.0
    {
    swipeDirection = SwipeDirection.Down;
    }
    }
    else // Left
    {
    if (angle < 22.5f) // 0.0 - 22.5
    {
    swipeDirection = SwipeDirection.Up;
    }
    else if (angle < 67.5f) // 22.5 - 67.5
    {
    swipeDirection = SwipeDirection.UpLeft;
    }
    else if (angle < 112.5f) // 67.5 - 112.5
    {
    swipeDirection = SwipeDirection.Left;
    }
    else if (angle < 157.5f) // 112.5 - 157.5
    {
    swipeDirection = SwipeDirection.DownLeft;
    }
    else if (angle < 180.0f) // 157.5 - 180.0
    {
    swipeDirection = SwipeDirection.Down;
    }
    }

    return swipeDirection;
    }
    }

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;

    /// <summary>
    /// Input helper.
    /// SOURCE: http://answers.unity3d.com/answers/956579/view.html
    /// </summary>
    public static class InputHelper
    {
    private static TouchCreator lastFakeTouch;

    public static List<Touch> GetTouches()
    {
    List<Touch> touches = new List<Touch>();
    touches.AddRange(Input.touches);
    // Uncomment if you want it only to allow mouse swipes in the Unity Editor
    //#if UNITY_EDITOR
    if (lastFakeTouch == null)
    {
    lastFakeTouch = new TouchCreator();
    }
    if (Input.GetMouseButtonDown(0))
    {
    lastFakeTouch.phase = TouchPhase.Began;
    lastFakeTouch.deltaPosition = new Vector2(0, 0);
    lastFakeTouch.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    lastFakeTouch.fingerId = 0;
    }
    else if (Input.GetMouseButtonUp(0))
    {
    lastFakeTouch.phase = TouchPhase.Ended;
    Vector2 newPosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    lastFakeTouch.deltaPosition = newPosition - lastFakeTouch.position;
    lastFakeTouch.position = newPosition;
    lastFakeTouch.fingerId = 0;
    }
    else if (Input.GetMouseButton(0))
    {
    lastFakeTouch.phase = TouchPhase.Moved;
    Vector2 newPosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    lastFakeTouch.deltaPosition = newPosition - lastFakeTouch.position;
    lastFakeTouch.position = newPosition;
    lastFakeTouch.fingerId = 0;
    }
    else
    {
    lastFakeTouch = null;
    }
    if (lastFakeTouch != null)
    {
    touches.Add(lastFakeTouch.Create());
    }
    // Uncomment if you want it only to allow mouse swipes in the Unity Editor
    //#endif

    return touches;
    }
    }

    using UnityEngine;
    using System.Reflection;
    using System.Collections.Generic;

    /// <summary>
    /// Touch creator.
    /// BASED ON: http://answers.unity3d.com/answers/801637/view.html
    /// </summary>
    public class TouchCreator
    {
    static BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
    static Dictionary<string, FieldInfo> fields;

    object touch;

    public float deltaTime { get { return ((Touch)touch).deltaTime; } set { fields["m_TimeDelta"].SetValue(touch, value); } }
    public int tapCount { get { return ((Touch)touch).tapCount; } set { fields["m_TapCount"].SetValue(touch, value); } }
    public TouchPhase phase { get { return ((Touch)touch).phase; } set { fields["m_Phase"].SetValue(touch, value); } }
    public Vector2 deltaPosition { get { return ((Touch)touch).deltaPosition; } set { fields["m_PositionDelta"].SetValue(touch, value); } }
    public int fingerId { get { return ((Touch)touch).fingerId; } set { fields["m_FingerId"].SetValue(touch, value); } }
    public Vector2 position { get { return ((Touch)touch).position; } set { fields["m_Position"].SetValue(touch, value); } }
    public Vector2 rawPosition { get { return ((Touch)touch).rawPosition; } set { fields["m_RawPosition"].SetValue(touch, value); } }

    public Touch Create()
    {
    return (Touch)touch;
    }

    public TouchCreator()
    {
    touch = new Touch();
    }

    static TouchCreator()
    {
    fields = new Dictionary<string, FieldInfo>();
    foreach (var f in typeof(Touch).GetFields(flags))
    {
    fields.Add(f.Name, f);
    //Debug.Log("name: " + f.Name); // Use this to find the names of hidden private fields
    }
    }
    }

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;

    [RequireComponent(typeof(SwipeManager))]
    public class InputController : MonoBehaviour
    {
    public Player OurPlayer; // Perhaps your playerscript?

    void Start()
    {
    SwipeManager swipeManager = GetComponent<SwipeManager>();
    swipeManager.onSwipe += HandleSwipe;
    swipeManager.onLongPress += HandleLongPress;
    }

    void HandleSwipe(SwipeAction swipeAction)
    {
    //Debug.LogFormat("HandleSwipe: {0}", swipeAction);
    if(swipeAction.direction == SwipeDirection.Up || swipeAction.direction == SwipeDirection.UpRight)
    {
    // move up
    if(OurPlayer != null)
    OurPlayer.MovePlayerUp();
    }
    else if (swipeAction.direction == SwipeDirection.Right || swipeAction.direction == SwipeDirection.DownRight)
    {
    // move right
    if (OurPlayer != null)
    OurPlayer.MovePlayerRight();
    }
    else if (swipeAction.direction == SwipeDirection.Down || swipeAction.direction == SwipeDirection.DownLeft)
    {
    // move down
    if (OurPlayer != null)
    OurPlayer.MovePlayerDown();
    }
    else if (swipeAction.direction == SwipeDirection.Left || swipeAction.direction == SwipeDirection.UpLeft)
    {
    // move left
    if (OurPlayer != null)
    OurPlayer.MovePlayerLeft();
    }
    }

    void HandleLongPress(SwipeAction swipeAction)
    {
    //Debug.LogFormat("HandleLongPress: {0}", swipeAction);
    }
    }
     
  6. LexPanin

    LexPanin

    Joined:
    Jan 10, 2016
    Posts:
    12
    Why we need this condition:


    Code (CSharp):
    1. else if (touch.phase == TouchPhase.Moved) // update the last position based on where they moved
    2. {
    3.     lp = touch.position;
    4. }
    5.  
    ?
     
  7. sirbob809

    sirbob809

    Joined:
    Feb 9, 2017
    Posts:
    1
    That section just updates the lp to the new location the "touch.phase = TouchPhase.Moved" informs the program that the finger has moved from it's location, and thus it updates the lp to the new touch.position.
     
  8. netlander

    netlander

    Joined:
    Nov 22, 2011
    Posts:
    26
    Thanks dude, saved me some time.
     
  9. ephdot

    ephdot

    Joined:
    May 16, 2013
    Posts:
    2
    Thank you for this. It was a great starting point. I tweaked it in a few places to suit my needs. First I added code to process a swipe in the moved event as well as the ended event. That way you don't have to wait for the swipe to complete to be considered a swipe. Once it is at 15 percent, it's a swipe. In order to make it so the ended event didn't also process a swipe that was handled by the moved, I added a boolean. Lastly, I added the condition for (Mathf.Abs(lp.y - fp.y) > dragDistance) into the swipe up/down logic because we used an OR at the top of the swipe's if statement, so we're really not sure what got us there (left/right or up/down). This really only help's prevent false down swipes which I was seeing on occasion. I did the same for the left/right with the x axis. If anyone wants my code for it, let me know.
     
  10. vidrik

    vidrik

    Joined:
    Jun 3, 2013
    Posts:
    1
    hi ephdot, please share your code ,it would help me and others,

    thanks too all
     
    Daevin likes this.
  11. Data1

    Data1

    Joined:
    Nov 18, 2017
    Posts:
    5
    I'm new to Unity but where in the code does it tell unity what object to move to the finger position? I'm making a pong game and trying to get the paddle to go up and down through touch.

    public float paddleSpeed = 1;
    public Vector3 playerPos;

    private Vector2 touchOrigin = -Vector2.one;


    // Update is called once per frame
    void Update()
    {
    float yPos = gameObject.transform.position.y + (Input.GetAxis("Vertical") * paddleSpeed);
    playerPos = new Vector3(-10, Mathf.Clamp(yPos, -18f, 10f), 0);
    gameObject.transform.position = playerPos;

    }

    This is what i have for the movement right now, but this is just keyboard
     
  12. HaRoStudio

    HaRoStudio

    Joined:
    Jan 12, 2018
    Posts:
    1
    Hi, i tried the code below and it worked, when i swipe my object moves, but it takes time ebfore it moves, its not smooth. How can i fix it?
     
  13. eneskoto

    eneskoto

    Joined:
    Jun 9, 2017
    Posts:
    1
    You sir are a saint.
    Thank you very much for this script it has saved me a ton of work, THANK YOU!
     
    MD_Reptile likes this.
  14. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,585
    No problem, glad I could help! :)
     
  15. Ebonicus

    Ebonicus

    Joined:
    Oct 31, 2016
    Posts:
    92
    Please share the new version.
     
  16. ephdot

    ephdot

    Joined:
    May 16, 2013
    Posts:
    2
    Sorry - I just saw this.

    I abandoned swipe gestures and went with buttons for Jump/Duck.

    I just checked and I must have tossed out the swipe script. My apologies.
     
  17. Sinec

    Sinec

    Joined:
    Apr 21, 2018
    Posts:
    1
    How do i make controls for Android
     
  18. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,585
    Yes.
     
    GameDevCouple_I likes this.
  19. alexey-semechko

    alexey-semechko

    Joined:
    Aug 7, 2018
    Posts:
    1
    Thank you very much! Very helpful code!
     
    MD_Reptile likes this.
  20. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,585
    No problem, good luck!
     
  21. Andergraw

    Andergraw

    Joined:
    Nov 28, 2016
    Posts:
    6
    Nice piece of code. Thank you very much!

     
    MD_Reptile likes this.
  22. Adishah11

    Adishah11

    Joined:
    Aug 10, 2015
    Posts:
    9
  23. ewokjedi

    ewokjedi

    Joined:
    Jan 14, 2019
    Posts:
    5
    There is a little mistake in this code. It only works if swipe is covering 15% of the height. But side swipes are not. So I added "dragDistandeW = Screen.width * 15/100" and added it to "if (Mathf.Abs(lp.x - fp.x) > dragDistanceW || Mathf.Abs(lp.y - fp.y) > dragDistance)". Thanks a lot anyway, this code really helped me :)