Sunday 30 March 2014

Unity Tips: Swipe controls for Android and iOS

I've been doing a bit of work in Unity lately, putting together a basic Android game to teach myself the basics. I wanted to use swipe controls to move the player, and I think I've come up with a pretty nice template I thought I'd share with any other beginners out there. It's based on this script by Sushanta Chakraborty, but I've made it a bit more powerful and responsive. A brief explanation is below for those still learning C#.

using UnityEngine;
using System.Collections;

public class SwipeControl : MonoBehaviour
{
    //First establish some variables
    private Vector3 fp; //First finger position
    private Vector3 lp; //Last finger position
    public float dragDistance;  //Distance needed for a swipe to register

    // Update is called once per frame
    void Update()
    {
        //Examine the touch inputs
        foreach (Touch touch in Input.touches)
        {
            if (touch.phase == TouchPhase.Began)
            {
                fp = touch.position;
                lp = touch.position;
            }
            if (touch.phase == TouchPhase.Moved)
            {
                lp = touch.position;
            }
            if (touch.phase == TouchPhase.Ended)
            {
                //First check if it's actually a drag
                if (Mathf.Abs(lp.x - fp.x) > dragDistance || Mathf.Abs(lp.y - fp.y) > dragDistance)
                {   //It's a drag
                    //Now check what direction the drag was
                    //First check which axis
                    if (Mathf.Abs(lp.x - fp.x) > Mathf.Abs(lp.y - fp.y))
                    {   //If the horizontal movement is greater than the vertical movement...
                        if (lp.x>fp.x)  //If the movement was to the right
                        {   //Right move
                            //MOVE RIGHT CODE HERE
                        }
                        else
                        {   //Left move
                            //MOVE LEFT CODE HERE
                        }
                    }
                    else
                    {   //the vertical movement is greater than the horizontal movement
                        if (lp.y>fp.y)  //If the movement was up
                        {   //Up move
                            //MOVE UP CODE HERE
                        }
                        else
                        {   //Down move
                            //MOVE DOWN CODE HERE
                        }
                    }
                }
                else
                {   //It's a tap
                    //TAP CODE HERE
                }

            }
        }
}

Ok, so what's happening here? 


  • First, we set up a load of variables. The private variables are for use within this script only; the public ones can be edited from the Unity inspector and other scripts. 
  • dragDistance is the distance a player must drag their finger/thumb for it to register as a swipe instead of a tap, and because it's a public variable you can set this in the inspector. In my game it's set at 5, but it depends on your device and game so experiment. REMEMBER TO SET THIS IN THE INSPECTOR OR THE CODE WILL NOT WORK.
  • Next we move into the Update function, which is called every step.
  • We examine every touch:
    • If the player has just touched their finger to the device, we set 'fp' and 'lp' to their finger's position.
    • If the player's finger is on the device but it's been there for more than one frame, we set 'lp' to their finger's current position.
    • If the player has just removed their finger from the device, we move on to the next bit (no need to record the position because it's going to be indistinguishable from its position in the previous step).
  • We compare the first and last finger positions ('fp' and 'lp') to see if the distance travelled is enough to qualify as a drag. The IF statement below is a little confusing-looking so let's break it down:
    • We could just subtract one point from the other (if lp-fp>dragDistance), but this has two problems:
      • This gives us the diagonal distance, which is always larger than either the horizontal or the vertical distance (thanks, Pythagoras). This means that a player's tap might be accidentally interpreted as a drag, even if it is less than our specified dragDistance. To solve this, we instead check both the horizontal distance (lp.x-fp.x) and the vertical distance (lp.y-fp.y) travelled by the finger, and if either of them is large enough we register a drag as having taken place. The '||' symbol means OR in C#.
      • Coordinates increase from left to right, meaning that if you drag from right to left the distance will be negative - the same applies to drawing up rather than down. To avoid this we instead use the 'absolute' distances; that is, their size regardless of their positive or negative status. The absolute value of -6 is 6; the absolute value of 6 is 6. 'Abs' is how we do this in C#, but we have to precede it with 'Mathf' to tell Unity what we're doing.
    • Thus, the statement compares both the absolute vertical distance and absolute horizontal distance travelled by the finger to our dragDistance; if either or both are larger we move on to the next step.
  • Now we need to check whether the player meant to swipe vertically or horizontally, which we do by comparing the absolute distances we saw in the previous step.
  • Having determined that, we check the direction of the swipe within each of these stages by comparing the final to the starting coordinates.
I've probably explained more than I need to there, but if you do have any questions please leave them below.

~Roxton.

3 comments:

  1. Hi, I have started learning unity right now. Here you have describe about swipe movement. I am looking for phone movement like you have in racing game.If you rotate your phone left the object moves into left and if you yo rotate right it will move in right. For example games like Temple runs and racing game where on phone movement object move. Can you please tell me how to achieve this kind of functionality in unity with sample code.

    ReplyDelete
  2. Great ! Very nice blog and excellent things exist in your blog content.
    website design melbourne | SEO services Melbourne

    ReplyDelete
  3. nicely explained. I have one question though. Swipes will work only when touch phase ends but I an trying to find a solution where if user drags his finger up and down game player should behave accordingly i.e. jump and slide. Problem is until user lifts his finger up its considered as one swipe and action performed will be based on last coordinate in phase.end

    ReplyDelete