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. |