# How do you 'flick' something?

This has been bugging me for about a week…how do you go about ‘flicking’ something? I want to make a simple 2D program that allows someone to select a point on the ipad and ‘flick’ towards a goal. Various 2D objects will be in the course (so, the physics classes will be used), and the ‘puck’ will bounce around.

Seems simple enough, but my rather poor flick code just isn’t producing any results. I get barely moving circles, not speedy flicked ones…

Borrowing from the physics sample I wrote this snippet. (Zoom library in use)


if touch.state == BEGAN then
startPos =zoom:getWorldPoint(vec2(touch.x, touch.y) )
End

if touch.state== MOVING then
pt =zoom:getWorldPoint(vec2(touch.x, touch.y) )
end

if touch.state==ENDED then
local sz=30
local gain = 2.0
local damp = .5
cir = createCircle(startPos.x, startPos.y, sz) --creates a physics circle
local diff = vec2(touch.x, touch.y) - startPos
local vel = cir:getLinearVelocityFromWorldPoint(pt)
cir:applyForce( (1/1) * diff * gain - vel * damp, vec2(touch.x, touch.y))



Why don’t you use a calculation with touch.delta... and say of the speed is above z pixels then it is a flick?

Getting flicks right is tricky. One big problem is that the final touch can have ended at any time in the last draw cycle. If it ended right at the start then the recorded position will be only slightly different to the previous position. This is then problematic if you compute the velocity as that will assume that the two events are a whole number of cycles apart. What you can do is compute the last-but-one velocity, or you can compute a “running” velocity. But you will need to use ElapsedTime (or DeltaTime) because the touch events might not come in one every draw cycle so you need to record. both the position and the time for the velocity computations.

Here’s my velocity code:

function Touch:instVelocity()
if self.deltatime > 0 then
return vec2(
self.touch.deltaX/self.deltatime,
self.touch.deltaY/self.deltatime
)
else
return vec2(0,0)
end
end

function Touch:meanVelocity()
if self.updatedat > self.createdat then
return vec2(
self.touch.x - self.firsttouch.x,
self.touch.y - self.firsttouch.y
)/(self.updatedat - self.createdat)
else
return vec2(0,0)
end
end

function Touch:velocity()
local dt = 0
local dx = 0
local dy = 0
local i
local n = 0
local rec = false
local vel = self.velocities
for k,v in ipairs(vel) do
n = n + 1
if v[3] > ElapsedTime - 2*self.velDelta then
rec = true
end
if i and v[3] > ElapsedTime - self.velDelta then
rec = false
end
if rec then
i = k
end
end
if i == 0 then
i = 1
end
dt = ElapsedTime - vel[i][3]
if dt == 0 then
return vec2(0,0)
end
dx = vel[n][1] - vel[i][1]
dy = vel[n][2] - vel[i][2]
return vec2(dx/dt,dy/dt)
end


These a part of my extended Touch class (so uses extra information than just the in-built touch object). instVelocity computes the velocity between the previous and current touch points so is subject to the above error. meanVelocity is the average velocity of the entire touch, from first event to current. velocity is a little more complicated. It finds a touch event in the current touch that is within a particular time period ago (as best it can) and computes the velocity between that and the current event. I find this works quite well.

@andrew_stacey, I’ve looked at your touch class, and it’s a bit heady…it’s good to know that this problem wasn’t as simple as I originally thought…I thought that I was making more out of it than was there. Good to see that I wasn’t wrong!

@jordan, I forgot there was a touch.delta. It’ll be good to see the new version of Codea with integrated help…

Hi Aciolino. Is this what you want?
If yes then the code is to define the 3 following functions to pass your pressed, moved and released events:

    controller6 = OneTouch{
pressed = function(v)
controller6.lastPos = v
controller6.speed = vec2(0,0)
speed = vec2(0,0)
steer = 1
pos = v
end,
moved = function(v)
pos = v
local dv = (v-controller6.lastPos)/DeltaTime
controller6.lastPos = v
controller6.speed = controller6.speed*0.8 + dv*0.2
end,
released = function(v)
speed = controller6.speed
end,
x0=0.41,x1=0.8,y0=0,y1=0.49,name="one touch => flick",nameSide="bottom"}


When you release your finger, ‘speed’ gives you the speed at this moment. You can grab the code there:
https://gist.github.com/4067678
There are many contollers in this file, so check for the ‘contoller6’ example in the main.

‘speed’ gives you the speed at this moment

Well, not quite. The value returned by speed is some amalgamation of all the speeds that have been read so far. At least, if I’m reading the code correctly. Suppose that there were three events: began, moved, and ended. Then at began the velocity is set to (0,0). At moved, it is set to (0,0)*.8 + dv*.2 where dv is the velocity of that event. Finally, at ended it is set to the previous value of the speed.

So if the touch was (0,0) -> (10,0) -> (12,3) and time was such that DeltaTime = 1 then our reported velocity would be (2,0) = .8*(0,0) + .2*(10,0).

This is correct. The goal of the .8* old+ 0.2*new is to smooth a little bit the speed over the 5 last values: it avoids the random problems you described above: the speed is then consistent with recent finger movement. It works fine (grab the code and check it). If you want to be really accurate, it is not exactly the 5 last: it is a time moving average with exponential memory loss of the past.

Yes, the general formula is:

v_n = \\sum_{j=1}^n .8^{n-j} * .2*u_j


(Since u_0 = 0)

What you can’t do with that is move an object into position and then flick it (which was the problem I encountered when I tried a naive flick method). Moreover, for that to work properly then you need to assume that DeltaTime is (effectively) constant. The average of the speeds is not the average speed!

Actually i do move it into the pos i want nd then flick it. Run the code, youll see it woks not too bad i think.

That is pretty much what I am looking for.

So…I’ve seen the VirtualStick / VirtualSlider stuff before…did you write OneTouch and TwoTouch yourself?

Yes. Actually I’ve started with some of Nat’s controllers, modified them a lot, and added several new interracting tools to the program, as i needed them: menus, info, oneTouch, twoTouch and confirmBox. I use this project to stock and test all those utilities and i use them as a dependency in my other projects.

.@aciolino btw, i remember you had the project to write some code to save/load 3d objects. Did you finilize it?

Yes, I did. I have an HTTPLoader class that can read and store. Local 3d objects. It doesn’t create 3d objects though. There is a cool tool out here that does CSG; that code is pretty. Awesome for creating 3d primitives! I use that often for placeholders,

I don’t have a gist or source backup (!) of my files yet, but glad to share…

Btw: what did you make TwoTouch for? Not sure i see the application.

TwoTouch i use: 1 touch = move, 2 touch = pinch,zoom,rotate around z axis (i use this in my planet simulation)

well if you give me a link to your library to save/load 3d data, i’ll be glad to get the code if you allow me to use it!

Here is a little game I created awhile ago. It uses a flick of the finger to shoot white balls at a red one. The object is to push the red ball through the red line. I’m not sure how accurate the flick controls the white balls as far as speed, but it seems to work OK here with very little math involved.


supportedOrientations(PORTRAIT)
displayMode(FULLSCREEN)
lineCapMode(SQUARE)

function setup()
tab={}
rcount=0
scount=0
screated=false
rcreated=false
createEdges()
end

function draw()
background(40, 40, 50)
showLines()
showText()
drawEdge()
drawRandom()
drawShots()
end

function showLines()
stroke(0,255,0)
strokeWidth(4)
line(0,300,WIDTH,300)
stroke(255,0,0)
strokeWidth(20)
line(300,HEIGHT,450,HEIGHT)
end

function showText()
fontSize(40)
fill(255,0,0)
if not rcreated then
text("Double tap screen for red ball.",WIDTH/2,HEIGHT/2+300)
end
str=string.format("Goals %4d            Shots %4d",rcount,scount)
fontSize(20)
fill(255)
text(str,WIDTH/2,HEIGHT/2-50)
str=string.format("Score %6.4f         (Goals / shot)",rcount/scount)
text(str,WIDTH/2,HEIGHT/2-100)
text("Flick shots from below this line to push",WIDTH/2,320)
text("the red ball through the red line at the top.",WIDTH/2,280)
end

function createEdges()
e1=physics.body(EDGE,vec2(0,0),vec2(0,1200))
e1.type=STATIC
e2=physics.body(EDGE,vec2(WIDTH,0),vec2(WIDTH,1200))
e2.type=STATIC
e3=physics.body(EDGE,vec2(0,HEIGHT),vec2(300,HEIGHT))
e3.type=STATIC
e4=physics.body(EDGE,vec2(450,HEIGHT),vec2(WIDTH,HEIGHT))
e4.type=STATIC
end

function drawEdge()
stroke(255)
strokeWidth(10)
line(0,0,0,HEIGHT)
line(WIDTH,0,WIDTH,HEIGHT)
line(0,HEIGHT,300,HEIGHT)
line(450,HEIGHT,WIDTH,HEIGHT)
end

function createRandom()
r1=physics.body(CIRCLE,30)
r1.gravityScale=.5
r1.x=math.random(WIDTH)
r1.y=HEIGHT-200
rcreated=true
end

function drawRandom()
if rcreated then
strokeWidth(0)
fill(255,0,0)
ellipse(r1.x,r1.y,60,60)
destroyRandom()
end
end

function destroyRandom()
if r1.y < 0 or r1.y>HEIGHT then
rcreated=false
tab={}
if r1.y>HEIGHT then
rcount = rcount + 1
end
r1:destroy()
end
end

function createShots()
scount = scount + 1
z=#tab+1
tab[z]=physics.body(CIRCLE,15)
tab[z].gravityScale=-.1
end

function drawShots()
fill(255)
for z=1,#tab do
ellipse(tab[z].x,tab[z].y,30,30)
end
destroyShots()
end

function destroyShots()
for z=1,#tab do
if tab[z].y > 1000 or tab[z].y < 0 then
tab[z]:destroy()
table.remove(tab,z)
return
end
end
end

function touched(t)
if not rcreated then
if t.tapCount==2 then
createRandom()
end
return
end
if t.state==BEGAN and t.y< 300 and rcreated then
createShots()
screated=true
z=#tab
tab[z].x=t.x
tab[z].y=t.y
x1=t.x
y1=t.y
end
if t.state==MOVING and screated then
if #tab>0 then
z=#tab
tab[z].x=t.x
tab[z].y=t.y
end
end
if t.state==ENDED and screated then
screated=false
if #tab>0 then
z=#tab
x2=t.x
y2=t.y
xd=x2-x1
yd=y2-y1
tab[z].linearVelocity=vec2(xd*5,yd*5)
end
end
end



you see that “*5” in your code? I did the same thing, too…seems that “5” was a magic number for both of us. Nt quite sure “why” 5 works well.

I tried playing with the default gravity and varous proerties of the physics object, but nothing really worked as well as just cramming a 5 in there.

@JVM38 - working on the HTTP / 3D upload concept. I’ll be able to do it pretty soon (a few days); I’m just cleaning up the Dropbox Upload code I have.

@aciolino

I originally tried doing all kinds of calculations, but nothing seemed to work right. I then just multiplied it by a number ranging from 2 to 10 and 5 was the most realistic.

.@aciolino thanks! Can you only save/load via http? Not locally on the ipad?