Search code examples
androidinputunity-game-enginetouchgestures

swipe gestures on android in unity


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;
            }
        }
    }
}
}

Solution

  • 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();
        }
    
    
    }