Swipe and Tap detection
Monkey Targets Forums/iOS/Swipe and Tap detection
| ||
Hi all, I just made a class to handle swipe and tap detection but I'm wondering if I've gone about this the best way: a swipe is based on distance traveled on finger up). Perhaps instead I should detect speed of swipe and check for a minimum distance traveled (with finger still down). Also current my tap is based on finger up but it would be nice to maybe have that on finger down and not have it confused with a swipe, but I don't think this doable in a decent way. For example I could say that if it's down for a couple of frames (or down up rapidly) that is a tap, but someone might hold it down for a bit at the start of a swipe and the code would think it was a tap. How are you handling this in your games? Are there any links to best practices for this type of thing? (like in Apple docs) I've been searching for a while but not found anything decent. Thx. '///////////////////////////////////////////////// 'TGestureControl '///////////////////////////////////////////////// Class TGestureControl Const SWIPE_NONE:Int = 0 Const SWIPE_UP:Int = 1 Const SWIPE_DOWN:Int = 2 Const SWIPE_LEFT:Int = 3 Const SWIPE_RIGHT:Int = 4 Const SWIPE_TAP:Int = 5 Field downCounter:Int = 0 Field minDistance:Int = 100 Field swipeType:Int = SWIPE_NONE Field tapMaxDistance:Int = 80 'measured diagonally Field tapMaxTime:Int = 30 'frames Field touchStartX:Float = -1 Field touchStartY:Float = -1 Method GetSwipe:Int() 'Return and clear the swipe type Local temp:Int = swipeType swipeType = SWIPE_NONE Return temp End Method Method Reset:Void() touchStartX = -1 touchStartY = -1 End Method Method Update:Void() If myGame.touchDown[0] Then 'Has the finger just been placed down? If touchStartX = -1 And touchStartY = -1 Then touchStartX = VTouchX(0) touchStartY = VTouchY(0) downCounter = 0 Else downCounter += 1 Endif Else If touchStartX <> -1 And touchStartY <> -1 Then 'Has it moved far enough to be a swipe yet? Local newX:Float = VTouchX(0) Local newY:Float = VTouchY(0) Local diffX:Float = newX-touchStartX Local diffY:Float = newY-touchStartY If diffX>0 And diffX>minDistance And diffX>Abs(diffY) Then swipeType = SWIPE_RIGHT Reset() Elseif diffX<0 And diffX<-minDistance And Abs(diffX)>Abs(diffY) Then swipeType = SWIPE_LEFT Reset() Elseif diffY>0 And diffY>minDistance And diffY>Abs(diffX) Then swipeType = SWIPE_DOWN Reset() Elseif diffY<0 And diffY<-minDistance And Abs(diffY)>Abs(diffX) Then swipeType = SWIPE_UP Reset() Else 'Is the distance small enough that we can call it a tap? If math.Sqrt(diffX*diffX+diffY*diffY)<=tapMaxDistance And downCounter<=tapMaxTime Then swipeType = SWIPE_TAP Else swipeType = SWIPE_NONE Endif Reset() Endif Endif Endif End Method End Class |
| ||
I've always taken the approach of first getting the touch-sequence start/end info & then interpreting it. A Touch Sequence ... STARTS : When TouchDown(0), and only TouchDown(0), becomes True ENDS : When TouchDown(0) becomes False & a touch-sequence is in progress IS VOIDED: If TouchDown(n), where n >= 1, becomes True while a touch-sequence is in progress Touch Sequence Info: touchStartX, touchStartY, touchStartTime touchEndX, touchEndY, touchEndTime To interpret the touch sequence: _MAX_TAP_DELTA_TIME 'The max time allowed between start & end to be considered a SINGLE-TAP (anything longer is a HOLD event) _MAX_TAP_DELTA_DIST 'The max distance allowed between start & end to be considered a SINGLE-TAP _MAX_SWIPE_DELTA_TIME 'The max time allowed between start & end to still be considered a SWIPE (anything longer is a DRAG) _MIN_SWIPE_DELTA_DIST 'The min distance required between start & end for consideration as a SWIPE (must be larger than _MAX_TAP_DELTA_DIST) Some pseudo-code: for t = 0 until 5 if TouchDown( t ) touch-count+=1 end select touch-count case 1 if TouchDown( 0 ) if not touch-in-progress touch-in-progress = True touchStartX = TouchX touchStartY = TouchY touchStartTime = Millisecs ' just in case touch-sequence ends before next update touchEndX = TouchX touchEndY = TouchY touchEndTime = Millisecs else touchEndX = TouchX touchEndY = TouchY touchEndTime = Millisecs end else touch-in-progress = false end case 0 if touch-in-progress touch-in-progress = False delta-x = Abs( touchStartX - touchEndX ) delta-y = Abs( touchStartY - touchEndY ) delta-time = Abs( touchStartTime - touchEndTime ) ' check for single tap if ((delta-x <= _MAX_TAP_DELTA_DIST) and (delta-y <= _MAX_TAP_DELTA_DIST)) and (delta-time <= _MAX_TAP_DELTA_TIME) ' is a single-tap ' check for swipe else if ((delta-x >= _MIN_SWIPE_DELTA_DIST) or (delta-y >= _MIN_SWIPE_DELTA_DIST)) and (delta-time <= _MAX_SWIPE_DELTA_TIME) if delta-x >= delta-y If end-x < start-x ' swipe left else ' swipe right end else if end-y < start-y ' swipe up else ' swipe-down end end end end default touch-in-progress = false end HTH |
| ||
Very interesting, thanks for sharing. Looks like you are handling taps the same as me (time and distance limitations) and also adding time to the swipe which I could also do. |
| ||
Hey guys, Why not use wrapped gesture recognizers? |
| ||
Has anyone done that for Monkey yet with a module? I don't want to fart around with Objective C. |
| ||
I've thought of using the iOS/Android gesture recognizes but as I long ago developed code to handle detection of taps/double-taps/drags/swipes/pinches, I kinda' consider it a solved problem and never seriously looked for another solution. |