Faster touch

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
I'm dealing with making a mini-game in my lemming clone that allows the player to click a button let's say 10 times as fast as he/she. So I want to measure the time between touch 1 and touch 2 etc and store the times.

However I'm not sure how to do this?

Could you perhaps use touch events? Currently I use touch x/y/down commands inside OnRender and poll the raw touch information. I'm not sure that this is the best place to place, It seem slow compared to other reaction games that I've had experience with, so I know there's a better way.

But that's where I am right now. I'm now thinking of trying to set OnUpdate to be 120 hz and move allt the touch commands into that part of the program.

Does anyone know how to solve this problem?

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
I made a test for that idea and it did not seem to work.

As a test I try to read the touch 10 times and count the number of times it's uniqe, in each OnUpdate (which is to 120hz in this case).

But the counter is never higher than 1 unique read...

Any ideas how to improve the speed a bit more?

Code:
``````Import mojo.app
Import mojo2

Function Main()
New MyApp
End

Class MyApp Extends App

Field counter:Int
Field counter2:Int
Field canvas:Canvas
Field x:Int[1000]
Field y:Int[1000]
Field index:Int
Field mx : Int
Field my : Int
Field ox : Int
Field oy : Int

Method OnCreate()
SetUpdateRate 120
SetSwapInterval = 1
canvas = New Canvas()
End

Method OnUpdate()

counter=counter+1

' This loop tries to read touch information 10 times each 120hz (Works only on Android as HTML has a maximized onUpdate of 60 fps like OnRender)
For Local temp := 0 To 10

ox = mx
oy = oy
mx = TouchX(0)
my = TouchY(0)
If (mx <> ox) And (my <> oy)
x[index] = mx
y[index] = my
index = index + 1
Endif

Next

End

Method OnRender()

counter2=counter2+1
canvas.Clear
canvas.DrawText " UPDATECOUNTER = "+counter/60+" RENDERCOUNTER = "+counter2/60,0,0
canvas.DrawText " Index this screen update = " + index,0,20
index = 0

canvas.Flush
End

End``````

Phil7

CX Code Contributor
3rd Party Tool Dev
Did you try using the amount of hits per frame of TouchHit() ?
This is not what you asked for, but maybe good enough for practical use as you can visualize the hit count only once per frame!?
code_language.cerberus:
``````Import mojo.app
Import mojo2

Function Main()
New MyApp
End

Class MyApp Extends App

Field counter:Int
Field counter2:Int
Field canvas:Canvas

Field hit:Int

Method OnCreate()
SetUpdateRate 3 ' -------------->>>> This is just to clearly show the difference if your clicking speed is slow ;-)
SetSwapInterval = 1
canvas = New Canvas()
End

Method OnUpdate()

hit = TouchHit()

If hit>0
counter = counter + hit
counter2 = counter2 + 1
Endif

End

Method OnRender()

canvas.Clear
canvas.DrawText " MultipleHitCnt =  "+counter+" OneHitPerFrameCnt "+counter2,0,0

canvas.Flush
End

End``````

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
It works on low 3 frames which is great. But Hit only gives the number of hits since the last frame? What if I need the x & y for all those hits between the each frame that you read? Are they also stored somewhere becuase I cannot use TouchX to read those retrospectively in the same way as Hit gives you the number of hits?

Phil7

CX Code Contributor
3rd Party Tool Dev
For some use cases you could just interpolate the x y coords from two frames to get a higher resolution, but if your want something like alternating fingers touching two buttons this wouldn't work.

I don't know if mulitple hit coords are stored somewhere, but I am pretty sure you cannot access them directly from within cerberus.

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Thanks so much, will try that. In case it does not work I might check in the source and see if I can save the x & y coord with each click as the number of hits are saved already hopefully it shouldn't be too hard.

But if one increase from 3 fps to 60 fps you will always get the same number on both parameters, so your test prooved a good point!
So there might not be any more touch events to collect, they must using some algorithm instead. Interpolation or something like you said. Thanks again!

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Is there a possibility to get exact timetags when something happened? That would make it possible to improved the interpolation

SLotman

Active member
3rd Party Module Dev
Doesn't Millisecs() work?

Phil7

CX Code Contributor
3rd Party Tool Dev
Not with cerberus directly. Let's say you have 3 hits from one frame to another, you can only get the time where you called KeyHit() and not when exactly those hits occurred. I frankly don't know if or which target support provide possibilities to do something like this.

SLotman

Active member
3rd Party Module Dev
Do not use Keyhit, use KeyDown and only get the next time after a KeyDown(KEY) = false

SLotman

Active member
3rd Party Module Dev
Something like this (pseudo-code below)

code_language.cerberus:
``````Class TimeStamp
Global list:List = new List<TimeStamp>

Field id
Field time

Method New(id, time)
Self.id = id
Self.time = time
End Method
End Class

id = 0

if button.state = DOWN then
if KeyDown(KEY) = false then
button.state = UP
id+=1
end if
else
if KeyDown(KEY) then
ts = new TimeStamp ( id, Millisecs() )
button.state = DOWN
end if
end if``````

Phil7

CX Code Contributor
3rd Party Tool Dev
The problem is where to put those calls. If you do it in OnUpdate() you can't measure smaller durations than the delta time.
So for a normal 60 fps this is 16 Millisecs and the accuracy error for this is about the same on top.

SLotman

Active member
3rd Party Module Dev
According to this Intel doc, touch response takes 100-500 ms, so 16ms is more than enough to detect any touch a user could possible do.
This delay seems to be even worse on Android/iOS, around 300ms (to detect if you just tap or if you are making a gesture).

In any case, 16ms should be more than enough.

Phil7

CX Code Contributor
3rd Party Tool Dev
Nice investigation!
I just was approaching this from the opposite direction. Looking at human movement speed it seems to be limited to around 20 hits per second.
Fastest typing is around 1000 strokes per minute and fastest drum rolls are done at about 1200. So we get an average of 50 ms.
I tried to start/stop my stopwatch on my phone and it was consistently possible to get below 100 ms intervalls. My guess is that gesture detection just needs much more time than a single touch detection.
To make this one clear: I am totally with you that in most cases 16+-16 ms is fine, but if you wanted to let's say track if someone can precisely tap to a song at high speed, it is far from accurate. Our ears seem to recognise differences like latency as small as 11 ms.

SLotman

Active member
3rd Party Module Dev
Well, as a last resort you could try setting the update rate to something like 120, so the logic would run twice as fast IF the computar can handle it - it will depend on what you're doing.

But I really don't know how each platform will behave with this. I remember things on Android being severely limited - one of my devices here, a Samsung Galaxy Tab 4, is locked at 30 FPS, no matter what I do. On the old "Windows Phone" target, the code was a mess, it would run as fast as possible, no matter what the update rate was.

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Ya I know desktop platforms always peaks the OnUpdate for me at 60 fps. Android and HTML I can't remember which or both allow higher than 60 fps. But the reading is still slower of course except on ios devices which gives you touch events amazingly quick. But not quick enough depending on what you need it for.

As a musician I can tell you that the response-time of a human is around 10 msec actually. After that you can tell that one thing happens before/after another. A chord starts to become a strum etc.
So when you think about that 60 fps (being 16 msec) that kinda makes it kinda good goal to strive for.
But what you usually get on Android is 60-100msec between the events.

Cerberus has a nice thing going on where it cleverly handles *some* Hit commands, not all but some.
What it allow is that you can get the count missed since the last time you read using Hit. Everyone knows that part, but ONTOP of that you use that as an index on the usual commands in retrospect to READ those after they actually happened. I need to try this a bit more.

Last edited: