- Home /
Finding the starting and ending coordinates of a flick / swipe on iOS
I'm having a hard time with Unity's iOS touch controls.
I'd like to Instantiate an object using the flick / swipe command with the object instantiating at the flick / swipe starting point and pointing at the flick / swipe end point.
The best I've managed is to use Input.touchCount > 0 to get startPoint = Input.GetTouch(0).position. The whole thing is nestled in Update so it constantly gets recalculated which is probably going to cause problems later.
For endPoint, I've written if(Input.GetTouch(0).phase == TouchPhase.Ended || Input.GetTouch(0).phase == TouchPhase.Canceled) then touchEnd = Input.GetTouch(0).position.
It doesn't work of course, so I was wondering - how can I get the starting points and ending points of a swipe?
Answer by jahroy · Nov 16, 2011 at 08:44 AM
I haven't programmed any swipe gestures yet, but here's how I plan to do it:
- define a speed threshold: the minimum speed (or delta distance) that determines a swipe
- each frame that has touchCount == 1, check if the speed is greater than the threshold
- if it is (and it wasn't the last frame) store the start position
- if it is not (and it was the last frame) store the end position
- then you would do whatever you do after a swipe
Ok... I'm bored.
Here's some tested exactly twice code.
I'm sure it needs tweaking, but it's a good start:
var swipeThresh : float = 1.2; var swipeStart : Vector2 = Vector2.zero; var swipeEnd : Vector2 = Vector2.zero; var swipeWasActive : boolean = false;
function Update () { if ( Input.touchCount == 1 ) { processSwipe(); } }
function OnGUI () { processSwipe(); drawStartBox(); drawEndBox(); }
function processSwipe () { if ( Input.touchCount != 1 ) { return; }
var theTouch : Touch = Input.touches[0];
/* skip the frame if deltaPosition is zero */
if ( theTouch.deltaPosition == Vector2.zero ) {
return;
}
var speedVec : Vector2 = theTouch.deltaPosition * theTouch.deltaTime;
var theSpeed : float = speedVec.magnitude;
var swipeIsActive : boolean = ( theSpeed > swipeThresh );
if ( swipeIsActive ) {
if ( ! swipeWasActive ) {
swipeStart = theTouch.position;
}
}
else {
if ( swipeWasActive ) {
swipeEnd = theTouch.position;
Debug.Log("Swipe Complete");
}
}
swipeWasActive = swipeIsActive;
}
function drawStartBox () { if ( swipeStart == Vector2.zero ) { return; }
/* don't forget to invert the y-coordinate */
var theY = Screen.height - swipeStart.y;
var theX = swipeStart.x;
var theW = 140;
var theH = 40;
var theRect : Rect = Rect(theX, theY, theW, theH);
GUI.Label(theRect, "Start");
}
function drawEndBox () { if ( swipeEnd == Vector2.zero ) { return; }
/* don't forget to invert the y-coordinate */
var theY = Screen.height - swipeEnd.y;
var theX = swipeEnd.x;
var theW = 140;
var theH = 40;
var theRect : Rect = Rect(theX, theY, theW, theH);
GUI.Label(theRect, "End");
}
I just gave this a try and it works surprisingly well...
I used a speed threshhold of 1.2, which can be adjusted in the Inspector.
Hope this helps!
I'm going to need to tinker with this code a bit to get it to work in my project - but it does what I've asked. Thanks for taking the time to reply and the helpful input!
Answer by kevork · Nov 16, 2011 at 09:34 AM
As you don't know whether something is a flick until after the user has both touched the screen and released, you need to save the touch data for a period of time. Using just Touch.deltaPosition only allows you to look one frame back, which is (hopefully) an extremely short amount of time.
The basic approach is to create a data structure that has all of the inputs of a specific finger id. You will want to save the Touch data and a timestamp. When any Touch is TouchPhase.Ended, then look through all that saved data to determine whether you have a flick. To determine whether you have a flick look backwards through your list of points and decide if the speed of input is a flick.
I don't understand why all this would be necessary (and my approach wouldn't work), but I guess I'll find out when I go to add it to my project soon. I don't have an iPad build set up right now...
At the very least for your approach you should iterate through all of the touches ins$$anonymous$$d of just looking at the list. When dealing with touches Input.mousePosition is the average position of all the touches on the screen, so if you detect a swipe with finger 1 and there are two other fingers on the screen, your start & end positions will not be at the location of the swipe. Additionally the start and end positions are a Vector2 not a float, so you want to save both the x & y positions, not just the x.
Finally, we found for our uses that the Touch.deltaPosition was not enough information to make a reliable decision regarding about whether there was a flick or not and what direction the user intended the flick to go in.
That's just sample/pseudo code thrown together to suggest a possible approach...
Input.mousePosition is a typo and was meant to be theTouch.position....
Since it's just example code I only deal with one touch and one direction for simplicity.
Obviously I'm not trying to provide a complete solution here...
Wow, looks like it's a lot more complex than I thought. Didn't seem like it would be so hard since there are a ton of developers out there using flick-based games, but when you're trying to distinguish between taps, holds, and other input methods then I guess it's necessary.
Will try a few more things out before marking an answer. Thanks for your input!
I wish I could do an iOS build right now... I had to restore my iPad recently and am having troubles with the provisioning stuff.
I would love to play with this... I just tested my code with Unity remote (after a few changes) and was pleasantly surprised with how well it seemed like it might be working.
It's hard to really test with Unity Remote....
Your answer
Follow this Question
Related Questions
iOS controls 1 Answer
Swipe & gesture controls for android 1 Answer
Simultaneous Touch Drag Controls 0 Answers
How do I fix my Swiping Down Errors? 1 Answer
Question about IOS controls 0 Answers