Touch screen horizontal or vertical swipe

I need to move an object on a grid board, by a standard distance (eg 1 unit horizontally or vertically), depending on whether I swipe one finger horizontally or vertically. The distance is fixed as I mentioned and the direction will depend on whether I move from bottom to top, from left to right or vice versa.

As I understand I will have to use (or at least this could be a way to do it) the Touch.deltaPosition and the tan of the vector that my swipe will follow. This way, if I swipe from bottom to top, the vector that I follow has an angle fo 90degrees (in relation to the xy coordinate system of the board my object moves on) and its tan is infinite. Using if I will then tell my object to move one unit up if this kind of swipe is input.

The problem is I dont know how to script that, no matter how much I browse through the Script Reference and the Forum. Any hint would be very appreciated.

Alex :-)

You should check andee's post over at the forums. It worked great for me (for a similar situation):

http://forum.unity3d.com/threads/48601-Swipe-help-please?highlight=swipe

(4th post down)

Just check for touch.position.x as well.

TO ANYONE WHO HAS/HAD THE SAME QUESTION:

I actually took andee’s code, transphered it to C#, and improved it a litte:

The major difference in contrast to andee’s script is, that for the swipe to be registered you dont have to wait till your finger leaves the touchscreen, and that you don’t have to swipe "totally horizonta"l (Just the x-difference gets measured → swiping is (way) more convinient).
As of now, this is as i find the way it is implemented in most games/apps nowdays.

//If you’d like to do the same for a vertical swipe, just exchange every “.x” with a “.y” .

Feel free to use :slight_smile:
-Toonk

public float minSwipeDist, maxSwipeTime;
bool couldBeSwipe;

IEnumerator checkHorizontalSwipes () //Coroutine, wich gets Started in "Start()" and runs over the whole game to check for swipes
		{
				while (true) { //Loop. Otherwise we wouldnt check continoulsy ;-)
						foreach (Touch touch in Input.touches) { //For every touch in the Input.touches - array...
			
								switch (touch.phase) {
								case TouchPhase.Began: //The finger first touched the screen --> It could be(come) a swipe
										couldBeSwipe = true;

										startPos = touch.position;  //Position where the touch started
										swipeStartTime = Time.time; //The time it started
										break;
				
								case TouchPhase.Stationary: //Is the touch stationary? --> No swipe then!
										couldBeSwipe = false;
										break;
								}

								float swipeTime = Time.time - swipeStartTime; //Time the touch stayed at the screen till now.
								float swipeDist = Mathf.Abs (touch.position.x - startPos.x); //Swipedistance

				
								if (couldBeSwipe && swipeTime < maxSwipeTime && swipeDist > minSwipeDist) {
										// It's a swiiiiiiiiiiiipe!
										couldBeSwipe = false; //<-- Otherwise this part would be called over and over again.

										if (Mathf.Sign (touch.position.x - startPos.x) == 1f) { //Swipe-direction, either 1 or -1.

												//Right-swipe

										} else {
					
												//Left-swipe
										}
								} 
						}
						yield return null;
				}

I had an issue with TouchPhase randomly being stationary in what I considered a fast valid swipe. I got around this issue by modifying andee’s code to require stationary to continuously be the phase for 6 frames before it’ll cancel.

Here’s the full code:

public class TouchGesture
{
    [System.Serializable]
    public class GestureSettings
    {
        public float minSwipeDist = 100;
        public float maxSwipeTime = 10;
    }

    private GestureSettings settings;
    private float swipeStartTime;
    private bool couldBeSwipe;
    private Vector2 startPos;
    private int stationaryForFrames;
    private TouchPhase lastPhase;

    public TouchGesture(GestureSettings gestureSettings)
    {
        this.settings = gestureSettings;
    }

    public IEnumerator CheckHorizontalSwipes(Action onLeftSwipe, Action onRightSwipe) //Coroutine, which gets Started in "Start()" and runs over the whole game to check for swipes
    {
        while (true)
        { //Loop. Otherwise we wouldnt check continuously ;-)
            foreach (Touch touch in Input.touches)
            { //For every touch in the Input.touches - array...
                switch (touch.phase)
                {
                    case TouchPhase.Began: //The finger first touched the screen --> It could be(come) a swipe
                        couldBeSwipe = true;
                        startPos = touch.position;  //Position where the touch started
                        swipeStartTime = Time.time; //The time it started
                        stationaryForFrames = 0;
                        break;

                    case TouchPhase.Stationary: //Is the touch stationary? --> No swipe then!
                        if (isContinouslyStationary(frames:6))
                            couldBeSwipe = false;
                        break;

                    case TouchPhase.Ended:
                        if (isASwipe(touch))
                        {
                            couldBeSwipe = false; //<-- Otherwise this part would be called over and over again.

                            if (Mathf.Sign(touch.position.x - startPos.x) == 1f) //Swipe-direction, either 1 or -1.   
                                onRightSwipe(); //Right-swipe
                            else
                                onLeftSwipe(); //Left-swipe
                        }
                        break;
                }
                lastPhase = touch.phase;
            }
            yield return null;
        }
    }

    private bool isContinouslyStationary(int frames)
    {
        if (lastPhase == TouchPhase.Stationary)
            stationaryForFrames++;
        else // reset back to 1
            stationaryForFrames = 1;

        return stationaryForFrames > frames;
    }

    private bool isASwipe(Touch touch)
    {
        float swipeTime = Time.time - swipeStartTime; //Time the touch stayed at the screen till now.
        float swipeDist = Mathf.Abs(touch.position.x - startPos.x); //Swipe distance
        return couldBeSwipe && swipeTime < settings.maxSwipeTime && swipeDist > settings.minSwipeDist;
    }
}

A script watching for swipes would look like:

public TouchGesture.GestureSettings GestureSetting;
private TouchGesture touch;

void Start()
{
    touch = new TouchGesture(this.GestureSetting);
    StartCoroutine(touch.CheckHorizontalSwipes(
        onLeftSwipe: () => { HideMenuHome(); },
        onRightSwipe: () => { ShowMenuHome(); }
        ));
}

Different sensitivity of TouchPhase.Stationary between devices is likely due to the DPI of the device. A better fix, than what I did here, might be to factor in the DPI to determine how many continuously stationary frames make it no longer a swipe.

SwipeControl does horizontal+vertical swiping: Website/video: GameAssets.net
Webplayer-Demo: SwipeControl Demo - GameAssets.net

@Leon700: Just pass System.Action along with the Swipe Direction Variable (onLeftSwipe or onRightSwipe in this case) as the argument.

Hey thanks for this post, helped me a lot.
I also found it easier to get the gestures from other scripts using a delegate.

    public enum SwipeDirection
    {
        None,
        Left,
        Right
    }
    private static SwipeDirection lastSwipe;
    public static Action<SwipeDirection> OnSwipeGesture;

------------

// then put this after you get the direction                       
 if (OnSwipeGesture != null)
      OnSwipeGesture.Invoke(lastSwipe);

made my life so much easier