Please help with flick motion

I have a code where I have a control panel (simplified to a white rectangle in the code below) that I want the user to be able to drag / flick.
I got the drag functionality to work pretty well, but I can’t get the flick working (acceleration caused by the drag) properly.

I think it tracked the problem to the way I calculate the acceleration in the lines:

local flickSpeed = ((localEventY-t.y0) / dT )\*.001  
local newYAfterAcelleration = setToWithinLimits((t.y+flickSpeed),lowestDragPos,highestDragPos   

But I can’t figure out how to solve it. Flicking down works fine, but unless the user makes a large movement, flick up works downwards.

Any help is appreciated! Thanks.

[code]

–helper function

local function setToWithinLimits(setTo,lowerLimit,upperLimit)
local result
if (setTo > upperLimit ) then result = upperLimit
elseif (setTo < lowerLimit) then result = lowerLimit
else result = setTo
end
return result
end

–objects

local localGroup=display.newGroup()

local panelGroup = display.newGroup()

localGroup:insert(panelGroup)

local panelBG = display.newRect(0,0,200,display.contentHeight*2)
panelBG:setFillColor(255,255,255)

local referenceObject=display.newCircle(20,100,5)
referenceObject:setFillColor(0,255,0)
panelGroup:insert(panelBG)
panelGroup:insert(referenceObject)


–drag function

local function dragPanel( event )
local t = event.target
local phase = event.phase

local highestDragPos = panelBG.contentHeight + display.contentHeight
local lowestDragPos = 0

local initialTimeMsec = system.getTimer()
local localEventX , localEventY = t.parent:contentToLocal(event.x,event.y)
if “began” == phase then
display.getCurrentStage():setFocus( t, event.id )
t.isFocus = true

– Store initial position
t.y0 = localEventY - t.y
initialTimeMsec = system.getTimer()
elseif t.isFocus then
if “moved” == phase then

local newY = localEventY - t.y0
t.y = setToWithinLimits(newY,lowestDragPos,highestDragPos)

elseif “ended” == phase or “cancelled” == phase then
– calc speed
local dT = system.getTimer() - initialTimeMsec

local flickSpeed = ((localEventY-t.y0) / dT )*.001
local newYAfterAcelleration = setToWithinLimits((t.y+flickSpeed),lowestDragPos,highestDragPos)

transition.to(t,{y=newYAfterAcelleration,transition=easing.outExpo})

display.getCurrentStage():setFocus( t, nil )
t.isFocus = false
end
end
return true
end

panelGroup:addEventListener(“touch”,dragPanel)

[/code] [import]uid: 33608 topic_id: 15467 reply_id: 315467[/import]

Nokia did a great writeup on kinetic scrolling: http://www.developer.nokia.com/Community/Wiki/Qt_Kinetic_scrolling_-_from_idea_to_implementation

Calculating velocity is important: v = d / t

http://ceres.hsc.edu/homepages/classes/astronomy/fall97/Mathematics/sec5.html [import]uid: 4596 topic_id: 15467 reply_id: 57182[/import]

Thanks. The Nokia article was an interesting reading.

I was able to solve the problem by recording the initial event.y position and using it to calculate the finger distance movement. I also used a new t.direction valuable to store the direction of the last finger movement.

here is the new code if it helps anyone in the future:

[code]

–helper function

local function setToWithinLimits(setTo,lowerLimit,upperLimit)
local result
if (setTo > upperLimit ) then result = upperLimit
elseif (setTo < lowerLimit) then result = lowerLimit
else result = setTo
end
return result
end

–objects

local localGroup=display.newGroup()

local panelGroup = display.newGroup()

localGroup:insert(panelGroup)

local panelBG = display.newRect(0,0,200,display.contentHeight*2)
panelBG:setFillColor(255,255,255)

local referenceObject=display.newCircle(20,100,5)
referenceObject:setFillColor(0,255,0)
panelGroup:insert(panelBG)
panelGroup:insert(referenceObject)


–drag function

local function dragPanel( event )
local t = event.target
local phase = event.phase

local highestDragPos = panelBG.contentHeight + display.contentHeight
local lowestDragPos = 0

local initialTimeMsec = system.getTimer()
local localEventX , localEventY = t.parent:contentToLocal(event.x,event.y)
if “began” == phase then
display.getCurrentStage():setFocus( t, event.id )
t.isFocus = true

– Store initial position
t.y0 = localEventY - t.y
t.lastY = localEventY
initialTimeMsec = system.getTimer()
elseif t.isFocus then
if “moved” == phase then

local newY = localEventY - t.y0
if t.y>newY then t.direction=-1 else t.direction=1 end
print(t.direction)
t.y = setToWithinLimits(newY,lowestDragPos,highestDragPos)

elseif “ended” == phase or “cancelled” == phase then
– calc speed
local dT = system.getTimer() - initialTimeMsec

local flickSpeed = t.direction*math.abs(((localEventY-t.lastY) / dT ))*.01
local newYAfterAcelleration = setToWithinLimits((t.y+flickSpeed),lowestDragPos,highestDragPos)

transition.to(t,{y=newYAfterAcelleration,transition=easing.outExpo})

display.getCurrentStage():setFocus( t, nil )
t.isFocus = false
end
end
return true
end

panelGroup:addEventListener(“touch”,dragPanel)

[/code] [import]uid: 33608 topic_id: 15467 reply_id: 57198[/import]

I was looking for the name of the app, it just came to me, It’s called “Mover Lite”, they do not use any physics, but hey use the flicking code, I think you can also find the source code to that app, it is a good read, (NOTE: it is written in Objective-C)

Maybe if I can find some time, I will try to port a few things off that into LUA/CoronaSDK.

cheers,

?:slight_smile: [import]uid: 3826 topic_id: 15467 reply_id: 58138[/import]