Search Unity

Single Tap/Double Tap script

Discussion in 'Scripting' started by TheChronicPhenix, Mar 30, 2011.

  1. TheChronicPhenix

    TheChronicPhenix

    Joined:
    Jan 14, 2010
    Posts:
    874
    Ok I think my last thread was kind of confusing. What I need is a script that will determine between a single tap and a double tap. I got it to recognize double taps fine, but every time a double tap gets called a single tap is also called because it counts the first tap, I need that not to happen, so basically I need it to say "After (so and so button) is pressed if it is pressed again within a certain time, then double tap, otherwise single tap" It seems so easy but for the life of me I can't get it to work, any help would be great. Thanks.
     
  2. TheChronicPhenix

    TheChronicPhenix

    Joined:
    Jan 14, 2010
    Posts:
    874
    I FINALLY GOT IT!!!! (sorry, but its been a very very frustrating problem for me), heres the code I used

    Code (csharp):
    1. var tapping : boolean;
    2. var LastTap : float;
    3. var tapTime : float;
    4.  
    5.  
    6. function Update(){
    7. if(Input.GetKeyDown("f")){
    8. if(!tapping){
    9. tapping = true;
    10. SingleTap();
    11. }
    12. if((Time.time - LastTap) < tapTime){
    13. Debug.Log("DoubleTap");
    14. tapping = false;
    15. }
    16. LastTap = Time.time;
    17. }
    18. }
    19.  
    20. function SingleTap(){
    21. yield WaitForSeconds(tapTime);
    22. if(tapping){
    23. Debug.Log("SingleTap");
    24. tapping = false;
    25. }
    26. }
     
    takito likes this.
  3. deadfire52

    deadfire52

    Joined:
    Jun 15, 2011
    Posts:
    101
    Thanks Astrauk, I added a few things to make it work with iOS devices:

     
  4. DataLohr

    DataLohr

    Joined:
    Sep 22, 2013
    Posts:
    1
    Hello,

    i got a slightly different way to do this:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class DoubleTapTest : MonoBehaviour
    5. {
    6.     float _doubleTapTimeD;
    7.  
    8.     // Update is called once per frame
    9.     void Update()
    10.     {
    11.         bool doubleTapD = false;
    12.  
    13.         #region doubleTapD
    14.  
    15.         if (Input.GetKeyDown(KeyCode.D))
    16.         {
    17.             if (Time.time < _doubleTapTimeD + .3f)
    18.             {
    19.                 doubleTapD = true;
    20.             }
    21.             _doubleTapTimeD = Time.time;
    22.         }
    23.  
    24.         #endregion
    25.  
    26.         if (doubleTapD)
    27.         {
    28.             Debug.Log("DoubleTapD");
    29.         }
    30.     }
    31. }
    you just need the doubleTapTime float variable for the time between the tappings and the Region doubleTap to detect the wanted tap.

    in this example i set a local bool doubleTapD = true if the tapping is within .3f seconds (and make sure to set it false before detecting the tapping again in line 10, wich is also the local declaration)

    some lines after, i just debug.log an information if the doubleTapD actualy is true.

    you also just could start a function to do whatever you want in line 18.


    to add detectoin for another key you just have to duplicate the time variable float _doubleTapTimeD; and rename it to e.g. float _doubleTapTimeArrowUp;

    then duplicate the region #region doubleTapD, rename all the variables in there and just change the KeyCode.D to KeyCode.ArrowUp or whatever you want.


    so long, happy tapping ;)
     
    Last edited: Oct 30, 2013
    Acengia, ZoraMikau and sushanta1991 like this.
  5. ben-rasooli

    ben-rasooli

    Joined:
    May 1, 2014
    Posts:
    40
    I came up with a slightly different approach. The difference is using StopCoroutine().
    Code (CSharp):
    1.     float touchDuration;
    2.     Touch touch;
    3.     void Update() {
    4.         if(Input.touchCount > 0){ //if there is any touch
    5.             touchDuration += Time.deltaTime;
    6.             touch = Input.GetTouch(0);
    7.  
    8.             if(touch.phase == TouchPhase.Ended && touchDuration < 0.2f) //making sure it only check the touch once && it was a short touch/tap and not a dragging.
    9.                 StartCoroutine("singleOrDouble");
    10.         }
    11.         else
    12.             touchDuration = 0.0f;
    13.     }
    14.  
    15.     IEnumerator singleOrDouble(){
    16.         yield return new WaitForSeconds(0.3f);
    17.         if(touch.tapCount == 1)
    18.             Debug.Log ("Single");
    19.         else if(touch.tapCount == 2){
    20.             //this coroutine has been called twice. We should stop the next one here otherwise we get two double tap
    21.             StopCoroutine("singleOrDouble");
    22.             Debug.Log ("Double");
    23.         }
    24.     }
     
    Last edited: Jul 27, 2014
    game786on, Gdakkutlu, audry and 3 others like this.
  6. zagmodell

    zagmodell

    Joined:
    Dec 27, 2012
    Posts:
    22
    ben.rasooli, Sharing this wonderful stuff is an act of unmeasurable generocity and kindness. You got BIIIIIG cohones, man .
     
    ben-rasooli likes this.
  7. Kerihobo

    Kerihobo

    Joined:
    Jun 26, 2013
    Posts:
    65
    Hi, what would the non-touchscreen version of this?

    Thanks
    Regan
     
  8. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    495
    First of all ,Thank you so much for real gem.....Kudos......Though it also count tap if user presses UI Buttons.How can we avoid this behavior ?
     
  9. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    495
    Hi again,I found the solution to my problem,

    You just need to add little validation code before starting coroutine

    Code (CSharp):
    1.  
    2. if (EventSystem.current.currentSelectedGameObject == null)
    3.  {
    4.        if (myTouch.phase == TouchPhase.Ended && touchDuration < 0.2f)
    5.         {
    6.                StartCoroutine(singleOrDouble());
    7.          }
    8. }
    The above line will instantly return any Event System bound game object user has clicked else it returns null.
    Hope it helps someone with similar problem like mine

    PS: The above code is influenced by Tim C's suggestion ,I found in this thread http://forum.unity3d.com/threads/4-6-how-to-detect-if-any-gui-element-has-been-clicked-on.263473/
     
    ben-rasooli likes this.
  10. bendableposeable

    bendableposeable

    Joined:
    Jul 30, 2016
    Posts:
    1
    @ben-rasooli thank you man, used a modified version of your solution to get something similar that i needed, thanks so much for contributing to the community
     
    ben-rasooli likes this.
  11. misher

    misher

    Joined:
    Apr 22, 2016
    Posts:
    19
    Here is a new approach using recent unity features. Make sure to have some Raycaster in your Scene. For UI, Graphics Raycaster is created by default within Canvas object, for 3d you may need to add Physics Raycaster to the Camera (also collider is needed on 3d object)
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Events;
    3. using UnityEngine.EventSystems;
    4.  
    5. public class TapsEvents : MonoBehaviour, IPointerDownHandler {
    6.  
    7.     // You can add listeners in inspector
    8.     public UnityEvent OnSingleTap;
    9.     public UnityEvent OnDoubleTap;
    10.  
    11.  
    12.     float firstTapTime = 0f;
    13.     float timeBetweenTaps = 0.2f; // time between taps to be resolved in double tap
    14.     bool doubleTapInitialized;
    15.  
    16.     public void OnPointerDown(PointerEventData eventData)
    17.     {
    18.         // invoke single tap after max time between taps
    19.         Invoke("SingleTap", timeBetweenTaps);
    20.  
    21.         if (!doubleTapInitialized)
    22.         {
    23.             // init double tapping
    24.             doubleTapInitialized = true;
    25.             firstTapTime = Time.time;
    26.         }
    27.         else if (Time.time - firstTapTime < timeBetweenTaps)
    28.         {
    29.             // here we have tapped second time before "single tap" has been invoked
    30.             CancelInvoke("SingleTap"); // cancel "single tap" invoking
    31.             DoubleTap();
    32.         }
    33.     }
    34.  
    35.     void SingleTap()
    36.     {
    37.         doubleTapInitialized = false; // deinit double tap
    38.  
    39.         // fire OnSingleTap event for all eventual subscribers
    40.         if(OnSingleTap != null)
    41.         {
    42.             OnSingleTap.Invoke();
    43.         }
    44.     }
    45.  
    46.     void DoubleTap()
    47.     {
    48.         doubleTapInitialized = false;
    49.         if(OnDoubleTap != null)
    50.         {
    51.             OnDoubleTap.Invoke();
    52.         }
    53.     }
    54.  
    55. }
     
  12. LucianoAlmeida

    LucianoAlmeida

    Joined:
    May 1, 2017
    Posts:
    2
    Thanks misher for this straightforward example. That was just what I needed.
     
    milkymomo and biodam like this.
  13. odin8958

    odin8958

    Joined:
    Aug 2, 2017
    Posts:
    2
    i wrote a simple logic and its working f9 :)

    int tapCount = 0;
    public void tapActionMethod () {
    if(tapCount >=2)
    return;
    if(tapCount <= 0)
    Invoke( "TapCheck", 0.3f );
    tapCount++;
    }

    void TapCheck () {
    switch (tapCount) {
    case 1:
    Debug.Log("single tap");
    break;
    case 2:
    Debug.Log("Double tap");
    break;
    }
    tapCount = 0;
    }
     
    igrize likes this.
  14. fattak

    fattak

    Joined:
    Dec 23, 2018
    Posts:
    4
    This script is very useful and easy to use in project, thank you!
     
  15. Meresman

    Meresman

    Joined:
    Sep 15, 2019
    Posts:
    9
    Thanks!
    Can you please share on which object you place this script usually?
    How do you subscribe to those events? also how do you reset the detection (After you trigger a click or a double click you can't trigger it again..)?
     
  16. Faizan65

    Faizan65

    Joined:
    Sep 12, 2020
    Posts:
    5
    My situation was bit tricky because my game used a continuous hold and move for player movement and double tap for jump.

    here is my code.

    Code (CSharp):
    1.  
    2. #region DoubleTapChecker  
    3.     float StartTime;
    4.     float EndTime;
    5.     int tapCounter=0;
    6.     private void LateUpdate()
    7.     {
    8.         if (Input.GetTouch(0).phase==TouchPhase.Began)
    9.         {
    10.             Debug.Log(Time.time);
    11.             StartTime = Time.time;
    12.         }
    13.         if (Input.GetTouch(0).phase == TouchPhase.Ended)
    14.         {
    15.             EndTime = Time.time;
    16.             Debug.Log(Time.time);
    17.         }
    18.         if (EndTime-StartTime<0.2f && EndTime - StartTime > 0f)
    19.         {
    20.             tapCounter++;
    21.             EndTime = 0f;
    22.             StartTime = 0f;
    23.             StartCoroutine(Countdown());
    24.             Debug.Log("Tap Counter = " + tapCounter);
    25.         }
    26.  
    27.     }
    28.     private IEnumerator Countdown()
    29.     {
    30.         yield return new WaitForSeconds(0.7f);
    31.         tapCounter = 0;
    32.     }
    33. #endregion
    I actually mixed the logics posted by few other people on forum made one new for me.