Faster touch

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
715
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
Joined
Jan 2, 2020
Messages
715
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

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
602
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
Joined
Jan 2, 2020
Messages
715
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

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
602
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
Joined
Jan 2, 2020
Messages
715
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
Joined
Jan 2, 2020
Messages
715
Is there a possibility to get exact timetags when something happened? That would make it possible to improved the interpolation
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
602
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
Joined
Jul 3, 2017
Messages
173
Do not use Keyhit, use KeyDown and only get the next time after a KeyDown(KEY) = false ;)
 

SLotman

Active member
3rd Party Module Dev
Joined
Jul 3, 2017
Messages
173
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
        list.AddLast(Self)
    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

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
602
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
Joined
Jul 3, 2017
Messages
173
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

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
602
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
Joined
Jul 3, 2017
Messages
173
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
Joined
Jan 2, 2020
Messages
715
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:
Top Bottom