Simple touch counter not working

Hi. I tried posting this question on the “answers” forum but got no reply, so I’m trying it here. I’m totally new to Unity and Android development, and I’m trying to make a simple program that counts the touches on an Android mobile device. So what I am trying to do is count every time the user “taps” the screen, meaning that the touch is counted only once when the user touches the screen then lifts his finger off the screen. And if the user holds their touch for more than 3 seconds, I want to count the number of touches for every frame up until the user lifts his finger.

I have also made a reset function that is linked to a button, so that I can reset the number of counts to 0 when I click the button.

The problem is that when I run the app on my phone, when I touch the first time, the counter goes up by 1, then it does not count for 3 seconds no matter what I do (even though touches are being registered in the phone). After the 3 seconds it begins to count touches continuously, but at a slower rate (maybe because the fps drops).

What I have figured out is that line 28,
if (touch.phase == TouchPhase.Ended) { touchStarted = false; numTouch = 1000000000; }, is never reached for some reason. BUT if I click the reset button, which calls the resetCounts() method, the if (touch.phase == TouchPhase.Ended) is reached and numTouch becomes 100000000. After the reset button is clicked, the app does not count for another 3 seconds, and then seems to count touches every frame afterwards.

I am completely lost in why this program is behaving so strangely, and would like to get help. I thank you in advance and will give more information that is needed.

+I also wonder how other people are debugging their Android apps. I tried Unity Remote5 but it doesn’t work, so currently I build and install the app on my mobile device every time I want to run my program. This is also why I set numCount to 100000000 in the code; so that I can sort of debug my program on my phone.

[LIST=1]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class TouchCounter: MonoBehaviour
{
    public Text touchCountTextBox;
    public static int numTouch = 0;
    private static bool touchStarted = false;
    private static float touchStartTime = 0.0f;
    private static float touchDelay = 3.0f; //time the user has to hold down touch for fast count to start(counts touch every frame)
    private static Touch touch;

    // Update is called once per frame
    void Update()
    {
            if (Input.touchCount > 0)
            {
                if (!touchStarted)
                {
                    touchStarted = true;
                    touch = Input.GetTouch(0);
                    touchStartTime = Time.time;
                    numTouch++;
                }
                if (touch.phase == TouchPhase.Ended)
                {
                    touchStarted = false;
                    numTouch = 1000000000;
                }
                //if user holds down touch, count touch every frame
                else if (Time.time - touchStartTime >= touchDelay)
                {
                    countTouchFast();
                }
            }
     
        touchCountTextBox.text = "" + numTouch;
    }

    //counts number of fingers on screen every second
    void countTouchFast()
    {
        numTouch += Input.touchCount;
    }

    public void resetCounts()
    {
        touch = Input.GetTouch(0);
        while (touch.phase != TouchPhase.Ended)
        {
            numTouch = 0;
        }
        Debug.Log("reseted");
    }
     
}

[/LIST]

A Touch object is actually a struct rather than a class.

What this means is when you do this:

touch = Input.touches[0];

What that did is copy the entire thing out to your local touch

That copy in your code will never be updated again except by you.

That’s why line 28 won’t be what you expect, as that is stale data from at least the previous frame, if not before.

Instead, perhaps move line 24 above to just before line 21, once you are sure there is at least one Touch inside of Input.touches.

I’d also recommend simplifying your time logic: don’t involve Time.time; the docs explicitly say that’s not intended for checking each frame:

I quote: “Regular (per frame) calls should be avoided: Time.time is intended to supply the length of time the application has been running for, and not the time per frame.”

Instead keep your own float, zero it, and then add Time.deltaTime to it every frame when the touch is active.

2 Likes

You’re only grabbing Input.GetTouch(0) on the first touch. That explains why touch.phase is never TouchPhase.Ended You need to grab Input.GetTouch(0) outside of your !touchStarted if statement, so you get the updated touch struct for each frame.

As for the counting speed changing between running the game in the editor and your device, yes of course the framerate is going to be different, and you’re adding once per frame. It might be a better idea to count the amount of time that has passed between frames and define the “points” in terms of how long the user has been holding the button down, rather than how many frames have passed. Frame count is not going to be consistent across different devices or even on the same device depending on what else is happening on that device at the time.

So for example, you assign 1 point for every 1/60th of a second that has passed while the user is holding down the touch. You can accomplish this by adding Time.deltaTime to a float variable every frame.

2 Likes

Thank you for your reply. It really helped a lot!

1 Like