Swipe Handling

For a project of mine I needed some simple code to detect swipes. I’ve seen people ask how to do it before, so I figured I’d go ahead and share it here (along with a simple code in main showing how it’s used)

Basically it works as so: A swipe must be of a certain length and time and not distance too far vertically or horizontally depending on the direction of the swipe. You can call Swipes:getSwipe() and it will return a vector based on how much you swiped (Ex a long swipe right would return vec2(3.2, 0) whereas a short swipe down would return vec2(0, -1.3)

Enough talking, here’s the code:


--# Main
-- Swiper

-- Use this function to perform your initial setup
function setup()
    swiper = Swipes()
    
    x = WIDTH / 2
    y = HEIGHT / 2
end

-- This function gets called once every frame
function draw()
    background(255, 255, 255, 255)
    
    stroke(0, 155, 255, 255) strokeWidth(2) noFill()
    
    local drawX, drawY = x % WIDTH, y % HEIGHT
    ellipse(drawX, drawY, 100)
end

function touched(t)
    -- Pass touch along to swipe handler
    swiper:touched(t)

    if t.state == ENDED then
        -- Get the swipe and use it to move the ball
        local s = swiper:getSwipe()
        tween(math.abs(0.2 * s.x), _G, { x = x + s.x * 100 }, tween.easing.linear)
        tween(math.abs(0.2 * s.y), _G, { y = y + s.y * 100 }, tween.easing.linear)
    end
end


--# Swipes
Swipes = class()

function Swipes:init()
    self.allowedMargin = WIDTH / 10
    self.swipeLen = WIDTH / 21
    self.allowedTime = 2
    
    self.firstTouch = nil
    self.lastTouch = nil
    self.startTime = nil
    self.endTime = nil
    
    self.swipe = vec2(0, 0)
end

function Swipes:getSwipe()
    local ret = self.swipe or vec2(0,0)
    self.swipe = vec2(0,0)
    
    return ret
end

function Swipes:findSwipes()
    if self.startTime == nil or self.endTime == nil or self.endTime - self.startTime > self.allowedTime then return end
    if self.firstTouch == nil or self.lastTouch == nil then self.firstTouch = nil self.lastTouch = nil return end
    
    if self.lastTouch.x - self.firstTouch.x >= self.swipeLen and math.abs(self.lastTouch.y - self.firstTouch.y) <= self.allowedMargin then
        -- Swiped right
        local amp = (self.lastTouch.x - self.firstTouch.x) / self.swipeLen
        self.swipe = vec2(amp, 0)
    elseif self.firstTouch.x - self.lastTouch.x >= self.swipeLen and math.abs(self.lastTouch.y - self.firstTouch.y) <= self.allowedMargin then
        -- Swiped left
        local amp = (self.lastTouch.x - self.firstTouch.x) / self.swipeLen
        self.swipe = vec2(amp, 0)
    elseif self.lastTouch.y - self.firstTouch.y >= self.swipeLen and math.abs(self.lastTouch.x - self.firstTouch.x) <= self.allowedMargin then
        -- Swiped up
        local amp = (self.lastTouch.y - self.firstTouch.y) / self.swipeLen
        self.swipe = vec2(0, amp)
    elseif self.firstTouch.y - self.lastTouch.y >= self.swipeLen and math.abs(self.lastTouch.x - self.firstTouch.x) <= self.allowedMargin then
        -- Swiped down
        local amp = (self.lastTouch.y - self.firstTouch.y) / self.swipeLen
        self.swipe = vec2(0, amp)
    end
    
    self.firstTouch = nil
    self.lastTouch = nil
end

function Swipes:touched(t)
    if t.state == BEGAN and self.firstTouch == nil then
        self.firstTouch = t
        self.startTime = ElapsedTime
    end
    
    if t.state == ENDED and self.lastTouch == nil then
        self.lastTouch = t
        self.endTime = ElapsedTime
        
        self:findSwipes()
    end
end

@JakAttak I looked thru my collection of code and found this swipe program. Thought I’d share it while we’re on the subject. Swipe in the direction you want the circle to go. Speed is determined by the length of the swipe.


displayMode(FULLSCREEN)

function setup()
    speed=30    -- set initial speed value
    swipe=vec3(0,0,0)    -- initialize swipe variable
    x=WIDTH/2    -- starting x location
    y=HEIGHT/2   -- starting y location
end

function draw()
    background(40,40,50)    -- set background color
    fill(255)    -- white color for circle
    text("Swipe for direction, length for speed",WIDTH/2,HEIGHT-100)
    ellipse(x,y,40)    -- draw a circle at x,y with size of 40
    if swipe.z>0 then    -- check if a swipe occured
        x=x+swipe.x*swipe.z    -- add x swipe speed to x value
        y=y+swipe.y*swipe.z    -- add y swipe speed to y value
    end  
end

function touched(t)
    if t.state==BEGAN then    -- start of swipe
        ts=vec2(t.x,t.y)    -- save touch start values
    end
    if t.state==ENDED then    -- end of swipe
        d=vec2(t.x,t.y):dist(vec2(ts.x,ts.y))    -- calculate swipe distance
        td=vec2(t.x-ts.x,t.y-ts.y):normalize()    -- x,y movement
        swipe=vec3(td.x,td.y,d/speed)    -- set swipe variable x,y,speed
    end       
end

Hi ! these codes looks really good ! But I think a swipe should be short in time (1 or 2 seconds max). Is there a way to handle that ?

@RyZum sure! You just save the time of the first and last touches, then compare them to see if the time in between is short enough. I’ve made the changes necessary in the code in the original post.

Simply change the allowedTime variable in the swipe class to however long you choose.

@Ryzum You could start a timer when the touch state equals BEGAN and then when the touch state equals MOVING you could check the timer. When the timer reaches the value you want (1 or 2 sec), stop changing the x and y values and process the swipe. When the touch state equals ENDED, you can either process the swipe if it you didn’t do it when MOVING, or ignore the swipe if you did it in MOVING.

Great ! Thanks.