swipe gestures on android in unity

13,728

The issue you're facing is because you've done your checks in the TouchPhase.Ended. What you want to do is perform your checks in TouchPhase.Moved, with a smaller change in value (you're using 80 in Ended, try something like 10 if you the code doesn't work)

Unity's documentation on TouchPhase http://docs.unity3d.com/ScriptReference/TouchPhase.html

    foreach(Touch touch in Input.touches)
    {

        if (touch.phase == TouchPhase.Began)
        {
            fingerStart = touch.position;
            fingerEnd  = touch.position;
        }
        if (touch.phase == TouchPhase.Moved )
        {
            fingerEnd = touch.position;

            if((fingerStart.x - fingerEnd.x) > 80 || 
               (fingerStart.x - fingerEnd.x) < -80) // Side to side Swipe
            {
                leftRight ++;
            }
            else if((fingerStart.y - fingerEnd.y) < -80 || 
                    (fingerStart.y - fingerEnd.y) > 80) // top to bottom swipe
            {
                upDown ++;

            }
            if(leftRight >= 3){

                leftRight = 0;
            }
            if(upDown >= 4){

                upDown = 0;
            }

            //After the checks are performed, set the fingerStart & fingerEnd to be the same
            fingerStart = touch.position;   

        }
        if(touch.phase == TouchPhase.Ended)
        {
            leftRight = 0;
            upDown = 0;
            fingerStart = Vector2.zero;
            fingerEnd = Vector2.zero;
        }




If you want to explicitly check for a pattern (i.e. left -> right -> left), rather than just checking if it's some lateral / vertical movement as the code you have will do, try the below code. Just remember to include System.Collentions.Generic & System.Linq namespaces

private Vector2 fingerStart;
private Vector2 fingerEnd;

public enum Movement
{
    Left,
    Right, 
    Up,
    Down
};

public List<Movement> movements = new List<Movement>();


void Update () {
    foreach(Touch touch in Input.touches)
    {

        if (touch.phase == TouchPhase.Began) {
            fingerStart = touch.position;
            fingerEnd  = touch.position;
        }

        if(touch.phase == TouchPhase.Moved) {
            fingerEnd = touch.position;

            //There is more movement on the X axis than the Y axis
            if(Mathf.Abs(fingerStart.x - fingerEnd.x) > Mathf.Abs(fingerStart.y - fingerEnd.y)) {

                //Right Swipe
                if((fingerEnd.x - fingerStart.x) > 0)
                    movements.Add(Movement.Right);
                //Left Swipe
                else
                    movements.Add(Movement.Left);

            }

            //More movement along the Y axis than the X axis
            else {
                //Upward Swipe
                if((fingerEnd.y - fingerStart.y) > 0)
                    movements.Add(Movement.Up);
                //Downward Swipe
                else
                    movements.Add(Movement.Down);
            }
            //After the checks are performed, set the fingerStart & fingerEnd to be the same
            fingerStart = touch.position;   

            //Now let's check if the Movement pattern is what we want
            //In this example, I'm checking whether the pattern is Left, then Right, then Left again
            Debug.Log (CheckForPatternMove(0, 3, new List<Movement>() { Movement.Left, Movement.Right, Movement.Left } ));
        }


        if(touch.phase == TouchPhase.Ended)
        {
            fingerStart = Vector2.zero;
            fingerEnd = Vector2.zero;
            movements.Clear();
        }
    }
}


private bool CheckForPatternMove (int startIndex, int lengthOfPattern, List<Movement> movementToCheck) {

    //If the currently stored movements are fewer than the length of the pattern to be detected
    //it can never match the pattern. So, let's get out
    if(lengthOfPattern > movements.Count)
        return false;

    //In case the start index for the check plus the length of the pattern
    //exceeds the movement list's count, it'll throw an exception, so lets get out
    if(startIndex + lengthOfPattern > movements.Count)
        return false;

    //Populate a temporary list with the respective elements
    //from the movement list
    List<Movement> tMovements = new List<Movement>();
    for(int i = startIndex; i < startIndex + lengthOfPattern; i++)
        tMovements.Add(movements[i]);

    //Now check whether the sequence of movements is the same as the pattern you want to check for
    //The SequenceEqual method is in the System.Linq namespace
    return tMovements.SequenceEqual(movementToCheck);
}



EDIT Added some more code as a sample

    //The idea of a pattern match is to check for the exact same set of swipe gesture.
    //This requires the following conditions to be met
    // (a) The List of movements that need to be checked must be at least as long as the List of movements to check against.
    // (b) The correct indices should be used for the startIndex. In this case I'm just using 0 as the startIndex.
    // (c) Remember to clear the List right after you get a true return from the method, otherwise the next return will most likely be a false. 

    //Example - Training set is Left -> Right -> Left (This is what we want to check)
    // Step 1 - User swipes LEFT, method returns false because there are too few Movements to check
    // Step 2 - User swipes RIGHT, method returns false (same reason as above)

    // Step 3a - User swipes RIGHT (L, R, R now) - false, incorrect pattern (L, R, R instead of L, R, L)
    // Step 3b - User swipes LEFT (L, R, L now) - TRUE, Correct pattern!

    //Immediately clear if Step 3b happens otherwise Step 4 will occur

    // Step 4 - User swipes L or R (direction is immaterial right now), and method will return FALSE
    // if you use the last three indexes!



    //Pre-populating the movements List with L, R, L
    movements = new List<Movement>()
    {
        Movement.Left,
        Movement.Right,
        Movement.Left
    };

    //Checking a match against an L, R, L training set
    //This prints true to the console
    Debug.Log (CheckForPatternMove(0, 3, new List<Movement>() { Movement.Left, Movement.Right, Movement.Left }  ));



Here's how my Update function looks like. Note the usage of GetMouseButton over Input.touch

void Update () {

    //Example usage in Update. Note how I use Input.GetMouseButton instead of Input.touch

    //GetMouseButtonDown(0) instead of TouchPhase.Began
    if (Input.GetMouseButtonDown(0)) {
        fingerStart = Input.mousePosition;
        fingerEnd  = Input.mousePosition;
    }

    //GetMouseButton instead of TouchPhase.Moved
    //This returns true if the LMB is held down in standalone OR
    //there is a single finger touch on a mobile device
    if(Input.GetMouseButton(0)) {
        fingerEnd = Input.mousePosition;

        //There was some movement! The tolerance variable is to detect some useful movement
        //i.e. an actual swipe rather than some jitter. This is the same as the value of 80
        //you used in your original code.
        if(Mathf.Abs(fingerEnd.x - fingerStart.x) > tolerance || 
           Mathf.Abs(fingerEnd.y - fingerStart.y) > tolerance) {

            //There is more movement on the X axis than the Y axis
            if(Mathf.Abs(fingerStart.x - fingerEnd.x) > Mathf.Abs(fingerStart.y - fingerEnd.y)) {
                //Right Swipe
                if((fingerEnd.x - fingerStart.x) > 0)
                    movements.Add(Movement.Right);
                //Left Swipe
                else
                    movements.Add(Movement.Left);
            }

            //More movement along the Y axis than the X axis
            else {
                //Upward Swipe
                if((fingerEnd.y - fingerStart.y) > 0)
                    movements.Add(Movement.Up);
                //Downward Swipe
                else
                    movements.Add(Movement.Down);
            }

            //After the checks are performed, set the fingerStart & fingerEnd to be the same
            fingerStart = fingerEnd;

            //Now let's check if the Movement pattern is what we want
            //In this example, I'm checking whether the pattern is Left, then Right, then Left again
            Debug.Log (CheckForPatternMove(0, 3, new List<Movement>() { Movement.Left, Movement.Right, Movement.Left } ));
        }
    }

    //GetMouseButtonUp(0) instead of TouchPhase.Ended
    if(Input.GetMouseButtonUp(0)) {
        fingerStart = Vector2.zero;
        fingerEnd = Vector2.zero;
        movements.Clear();
    }


}
Share:
13,728
Graeme MacDonald
Author by

Graeme MacDonald

Recent graduate of video game programming and design

Updated on June 22, 2022

Comments

  • Graeme MacDonald
    Graeme MacDonald almost 2 years

    I'm trying to get unity to recognize that I am swiping left to right, I have solved that but my issue is that it doesn't understand this till I lift my finger off the screen.

    My question is how would i make it so that it knows i went right and then left and then right again all without ever taking my finger of the screen

    Here is the code I have so far

    using UnityEngine;
    using System.Collections;
    
    public class Gestures : MonoBehaviour {
    
    private Vector2 fingerStart;
    private Vector2 fingerEnd;
    
    public int leftRight = 0;
    public int upDown = 0;
    
    void Update () {
        foreach(Touch touch in Input.touches)
        {
            if (touch.phase == TouchPhase.Began)
            {
                fingerStart = touch.position;
                fingerEnd  = touch.position;
            }
            if (touch.phase == TouchPhase.Moved )
            {
                fingerEnd = touch.position;
    
            }
            if(touch.phase == TouchPhase.Ended)
            {
                if((fingerStart.x - fingerEnd.x) > 80 || (fingerStart.x - fingerEnd.x) < -80) // Side to side Swipe
                {
                    leftRight ++;
                }
                else if((fingerStart.y - fingerEnd.y) < -80 || (fingerStart.y - fingerEnd.y) > 80) // top to bottom swipe
                {
                    upDown ++;
    
                }
                if(leftRight >= 3){
    
                    leftRight = 0;
                }
                if(upDown >= 4){
    
                    upDown = 0;
                }
            }
        }
    }
    }
    
  • Venkat at Axiom Studios
    Venkat at Axiom Studios over 9 years
    If the answer helped you, please mark it as the correct answer :)
  • Graeme MacDonald
    Graeme MacDonald over 9 years
    quick question, I'm trying the second code you posted but unity is throwing errors on the top two returns in CheckForPatternMove() saying "An object of a type convertible to `bool' is required for the return statement" I've tried setting both to false and true, but when i try testing to see if its detecting the (LRL)pattern its just always returning false I just copy pasted that second code into a new script and added the above mentioned namespaces what is it that I'm doing incorrectly
  • Venkat at Axiom Studios
    Venkat at Axiom Studios over 9 years
    Ah, the first one was my mistake. You need to return false in the first two checks (This is because there is no way the pattern can match). For your second issue, there's a high chance that you're using incorrect indices. I've edited my post above to detail how it's used exactly. Hopefully that should help you figure it out.
  • Venkat at Axiom Studios
    Venkat at Axiom Studios over 9 years
    Edit time ran out. Ah, the first one was my mistake. You need to return false in the first two checks For your second issue,it can be one of (a) incorrect indices being used for the check, (b) some additional points are being added in due to low tolerance (c) Input.touch returns quite a few points each time, this adds all of them. I've edited my post above to detail how I use the method. Hopefully that should help. Note that I generally use Input.GetMouseButton rather than Input.Touch. Mouse input works on mobile and returns a single point.
  • Venkat at Axiom Studios
    Venkat at Axiom Studios over 9 years
    Glad to be of assistance
  • Junaid Qadir Shekhanzai
    Junaid Qadir Shekhanzai almost 9 years
    @VenkatatAxiomStudios I'm using 80 as tolerance but i get jitters and as i swipe over the the gameobject the event keeps firing plus, the event fires even outside the game object which has this script it would be great if i you could tell how to tackle these issues
  • Venkat at Axiom Studios
    Venkat at Axiom Studios almost 9 years
    @JeyKeu The scripts don't check whether you are currently clicking/touching any GameObject. What you can do is include a Raycast in the Update function, and if the Raycast hits the GameObject you want to move, then calculate the swipe direction etc.