After doing some searching (Googling "unity mobile detect tap"), I found this as the top search result. @Mothil's answer gets us very close to the solution and OP's answer solves the question. However, OP's answer does not account for multiple taps. Also tracking the count of started touches, ended touches, and moved touches (e.g. int SCount, MCount, ECount
) is not necessary.
Instead we can directly loop through each touch and track each individual touch by its fingerId as @mothil did. For this we'll need two arrays to track a tap's characteristics: 1) short time delay, and 2) no movement. In the arrays below, the array index is the fingerId.
private float[] timeTouchBegan;
private bool[] touchDidMove;
We'll also need one more variable to store our desired tap time threshold. In my tests, I found that a threshold of 0.2f
works pretty well.
private float tapTimeThreshold = 0.2f;
In the Start()
function, we'll initialize this to hold 10 elements for 10 touches. This can be modified to however many touches desired.
In the Update()
function, we loop through each touch. If in TouchPhase.Began
then we set the timeTouchBegan[fingerIndex]
to the current time; we also set touchDidMove[fingerIndex]
to false.
If in TouchPhase.Moved
, we set touchDidMove[fingerIndex]
to true.
Finally, in TouchPhase.Ended
, we can calculate the tap time.
float tapTime = Time.time - timeTouchBegan[fingerIndex];
If the tap time is less than the threshold and the touch did not move then we have a verified tap.
if (tapTime <= tapTimeThreshold && touchDidMove[fingerIndex] == false)
{
// Tap detected at touch.position
}
Complete Script
Here's the full class:
public class TapManager : MonoBehaviour
{
private float[] timeTouchBegan;
private bool[] touchDidMove;
private float tapTimeThreshold = 0.2f;
void Start()
{
timeTouchBegan = new float[10];
touchDidMove = new bool[10];
}
private void Update()
{
// Touches
foreach (Touch touch in Input.touches)
{
int fingerIndex = touch.fingerId;
if (touch.phase == TouchPhase.Began)
{
Debug.Log("Finger #" + fingerIndex.ToString() + " entered!");
timeTouchBegan[fingerIndex] = Time.time;
touchDidMove[fingerIndex] = false;
}
if (touch.phase == TouchPhase.Moved)
{
Debug.Log("Finger #" + fingerIndex.ToString() + " moved!");
touchDidMove[fingerIndex] = true;
}
if (touch.phase == TouchPhase.Ended)
{
float tapTime = Time.time - timeTouchBegan[fingerIndex];
Debug.Log("Finger #" + fingerIndex.ToString() + " left. Tap time: " + tapTime.ToString());
if (tapTime <= tapTimeThreshold && touchDidMove[fingerIndex] == false)
{
Debug.Log("Finger #" + fingerIndex.ToString() + " TAP DETECTED at: " + touch.position.ToString());
}
}
}
}
}
Unity Tests
I tested this in my game using Unity Remote. In the screenshot below, you can see my debug console logs. I did a four finger tap. You can see that fingers 0 through 3 entered and left without any movement detected. A tap was detected for each finger and each tap's location was printed to the console.
