Best way to detect swipe in 4 directions

Hi all,

I was wondering if anybody had any ideas as the best way to detect swipe in four directions.

Here’s my thinking:

I want to make it so that when on the screen the user swipes left/right/up, different actions are run.  However, I would like it to detect the swipe without the user taking their finger off the screen.

For example, the player swipes left and holds their finger in a position to the left of their initial swipe, then the function will continue to execute.  Once the finger is released from the screen, the triggered function will stop.  The same thing will happen in the other four directions.

Another thing I want it to be able to do is detect swipes from current relative positions.

For example:

 1 2 3 

If the user starts their tap near the number two, and swipes towards one, without releasing their finger, then a specific function will be executed.  Then, if the person decides to swipe back to the right towards 2/3, another function will be executed (without the need to go past the initial start point, but rather from its previous position.

Here is what I currently have (from an example I found on the documentation):

local function handleSwipe( event ) if ( event.phase == "moved" ) then local dX = event.x - event.xStart local dY = event.y - event.yStart if ( dX \> 5 ) then --swipe right local spot = XRIGHT if ( event.target.x == XLEFT ) then spot = centerX end transition.to( player, { time=500, x=spot } ) elseif ( dX \< -5 ) then --swipe left local spot = XLEFT if ( event.target.x == XRIGHT ) then spot = centerX end transition.to( player, { time=500, x=spot } ) elseif ( dY \< -5 ) then if contact == 1 then --swipe up local spot = YLEFT if ( event.target.y == YRIGHT ) then spot = centerY end transition.to( player, { time=100, y=player.y - 10 } ) end end end return true end local button = display.newRect( 0, 0, 0, 0 ) button:setFillColor( 250/255, 250/255, 250/255 ) button.height = \_Y \* 2; button.width = \_X \* 2 button.x = 0; button.y = 0 button.anchorX = 0 button.isVisible = false button.isHitTestable = true button:addEventListener( "touch", handleSwipe )&nbsp;

Basically, when I swipe left the player moves all the way to the left.  I would rather have the player gradually move to the left (not all the way on the initial swipe), and the same for the right.  That way the user continues their established swipe to have the player continue movement until it hits the left/right borders.

I know this is very confusing, but any help is greatly appreciated.

Thanks

The unclear part is “the function will continue to execute”. Corona does not ever preempt the current thread of control, so there’s no way to just interrupt your function when another finger-move event arrives. And your function must return control to Corona so that it even has a chance to detect that another finger-move event has occurred. This is actually entirely doable with coroutines, but somewhat complex without significant support code.

Probably, the normal Corona way would be to change your requirement to “the function will get called repeatedly”.  In which case, maybe something like this would work for you:

function dragDirection(dispObj, up, down, left, right) local prevX, prevY local isFocus = false local dirFunc = nil local thisTimer = nil function repeatedly() if dirFunc ~= nil then dirFunc() end end function touchListener(event ) if event.phase == "began" then prevX = event.x; prevY = event.y dispObj:setFocus( self ) isFocus = true thisTimer = timer.performWithDelay(100, repeatedly, -1) elseif isFocus then if event.phase == "ended" or event.phase == "cancelled" then timer.cancel(thisTimer) dispObj:setFocus( nil ) isFocus = false dirFunc = nil elseif event.phase == "moved" then local deltaX = event.x - prevX local deltaY = event.y - prevY prevX = event.x; prevY = event.y if math.abs(deltaX) \> math.abs(deltaY) then if deltaX \> 0 then dirFunc = right else dirFunc = left end else if deltaY \> 0 then dirFunc = down else dirFunc = up end end end end return true end dispObj:addEventListener("touch", touchListener) end local function up() print("up") end local function down() print("down") end local function left() print("left") end local function right() print("right") end dragDirection(display.getCurrentStage(), up, down, left, right)

It calls one of the four direction functions via timer at a rate of 10 times per second.

@hi1,

Before I help, I need some clarification:

  1. Will the user be presented with visual queues showing where a touch is valid?  

     Your example implies this, but I’m not sure if you were you just using the 1,2,3 bit to elaborate.

  1. What do you expect to happen if the user swipes diagonally?

Ex: User swipes at 45 degree angle up-and-right. Ignore this.

  1. Is this input going to be used as a control scheme for a player character?  

If so, can you elaborate on what you want the player to do based on touches and swipes?

Ex 1: Swipe right and hold. - Player accelerates to the right while swiping, but slows down when the finger stops moving. 

Ex 2: Swipe right, pause, then swipe left. - Player accelerates to the right while swiping right, slows momentarily, then accelerates left during second part of swipe.  It takes a moment for the left acceleration to overcome the rightward velocity.

If not, can you tell us what you want to use this input for?  I ask, because you may be thinking, “I need to detect swipes to solve problem X, when we might be able to give you a better solution.”

Updated: ronburk did mention coroutines… removed link to said docs.

The unclear part is “the function will continue to execute”. Corona does not ever preempt the current thread of control, so there’s no way to just interrupt your function when another finger-move event arrives. And your function must return control to Corona so that it even has a chance to detect that another finger-move event has occurred. This is actually entirely doable with coroutines, but somewhat complex without significant support code.

Probably, the normal Corona way would be to change your requirement to “the function will get called repeatedly”.  In which case, maybe something like this would work for you:

function dragDirection(dispObj, up, down, left, right) local prevX, prevY local isFocus = false local dirFunc = nil local thisTimer = nil function repeatedly() if dirFunc ~= nil then dirFunc() end end function touchListener(event ) if event.phase == "began" then prevX = event.x; prevY = event.y dispObj:setFocus( self ) isFocus = true thisTimer = timer.performWithDelay(100, repeatedly, -1) elseif isFocus then if event.phase == "ended" or event.phase == "cancelled" then timer.cancel(thisTimer) dispObj:setFocus( nil ) isFocus = false dirFunc = nil elseif event.phase == "moved" then local deltaX = event.x - prevX local deltaY = event.y - prevY prevX = event.x; prevY = event.y if math.abs(deltaX) \> math.abs(deltaY) then if deltaX \> 0 then dirFunc = right else dirFunc = left end else if deltaY \> 0 then dirFunc = down else dirFunc = up end end end end return true end dispObj:addEventListener("touch", touchListener) end local function up() print("up") end local function down() print("down") end local function left() print("left") end local function right() print("right") end dragDirection(display.getCurrentStage(), up, down, left, right)

It calls one of the four direction functions via timer at a rate of 10 times per second.

@hi1,

Before I help, I need some clarification:

  1. Will the user be presented with visual queues showing where a touch is valid?  

     Your example implies this, but I’m not sure if you were you just using the 1,2,3 bit to elaborate.

  1. What do you expect to happen if the user swipes diagonally?

Ex: User swipes at 45 degree angle up-and-right. Ignore this.

  1. Is this input going to be used as a control scheme for a player character?  

If so, can you elaborate on what you want the player to do based on touches and swipes?

Ex 1: Swipe right and hold. - Player accelerates to the right while swiping, but slows down when the finger stops moving. 

Ex 2: Swipe right, pause, then swipe left. - Player accelerates to the right while swiping right, slows momentarily, then accelerates left during second part of swipe.  It takes a moment for the left acceleration to overcome the rightward velocity.

If not, can you tell us what you want to use this input for?  I ask, because you may be thinking, “I need to detect swipes to solve problem X, when we might be able to give you a better solution.”

Updated: ronburk did mention coroutines… removed link to said docs.