Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Making a double tap double the size of the jump in a responsive fashion.

Discussion in 'Scripting' started by gravesaad, Aug 23, 2023.

  1. gravesaad

    gravesaad

    Joined:
    Jul 7, 2023
    Posts:
    9
    Hi everybody,

    So i'm looking for a way to make a double tap that makes the movement/jump double its size while still being quick, as the gameplay relies on quickness to avoid obstacles with a fast moving camera, here are some videos for illustration.

    One tap should lead to something like this.

    https://drive.google.com/file/d/15HQ6CTxDnmDirjE2CWZX5EO7hd1lN8id/view?usp=drive_link

    Double tap should lead to something like this

    https://drive.google.com/file/d/15GCr9OIOa5nbG6hRmiGKN-ywhh0C7Kzd/view?usp=drive_link


    Here is my code :

    Code (CSharp):
    1.  
    2. public class Player : MonoBehaviour
    3. {
    4.  
    5.     float speed = 1f;
    6.     float jumpCount = 0f;
    7.     float jumpLimit = 5f;
    8.  
    9.     IEnumerator SingleOrDoubleTap(string position)
    10.     {
    11.         yield return new WaitForSeconds(0.2f);
    12.      
    13.  
    14.         if (tapCount == 1) // One tap
    15.         {
    16.            tapCount = 0;              
    17.            Debug.Log("Follow tap : Single");
    18.      
    19.  
    20.         }
    21.  
    22.  
    23.         else if (tapCount == 2) // two taps
    24.         {  
    25.  
    26.             Debug.Log("Follow tap : Double");
    27.             tapCount = 0;
    28.                 StopCoroutine("singleOrDouble");
    29.          
    30.        }
    31.  
    32.     }
    33.  
    34. void Update()
    35.     {    
    36.  
    37.         bottom = new Rect(0, 0, Screen.width, Screen.height / 4);
    38.         top = new Rect(0, Screen.height / 4, Screen.width, Screen.height / 1.35f);
    39.  
    40. if (Input.touchCount == 1)
    41.             {
    42.          
    43.             if (Input.GetTouch(0).phase == TouchPhase.Ended)
    44.                 {
    45.                     tapCount++;
    46.                     Debug.Log("Number taps is " + tapCount);
    47.            
    48.                     StartCoroutine(SingleOrDoubleTap("Top"));
    49.                     isJumping = true;
    50.             }
    51.  
    52.            
    53.  
    54.             if (!isJumping) // if the player isn't already jumping
    55.             {            
    56.  
    57.                 touch = Input.GetTouch(0);
    58.                 if (top.Contains(touch.position) && playerPosition.y   < 1.10f)
    59.                 {
    60.                     vertical += speed;                
    61.                     isJumping = true;
    62.  
    63.                 }
    64.  
    65.                 else if (bottom.Contains(touch.position) && playerPosition.y > -1.62f)
    66.                 {
    67.                     vertical -= speed;
    68.                     isJumping = true;
    69.  
    70.                 }
    71.  
    72.             }
    73.         }
    74.  
    75. void FixedUpdate()
    76.     {
    77.  
    78.  
    79.         if (timer >= waitTime)
    80.  
    81. /* The purpose of the timer is to avoid making erroneous jumps when pressing touch,
    82.             // whithout it touching can often lead to a jump immediately followed by another that gets the player in a wrong position
    83. */
    84.  
    85.         {        
    86.             timer = 0f;
    87.             waitTime = 0.2f;
    88.             isJumping = false;
    89.             jumpCount = 0f;
    90.  
    91.         }
    92.  
    93.         if (isJumping) {
    94.        timer += Time.fixedDeltaTime;    // if the jump has been launched, start the timer.
    95.  
    96.             if (jumpCount < jumpLimit) { jumpCount += 1f; }        
    97.         }
    98.      
    99.              
    100.             if (jumpCount ==  jumpLimit )
    101.  // The jump is made by raising the value speed each frame untill jumpCount reaches jumpLimit.
    102. // Then vertical is set to 0 so the player movement stops.
    103.             {
    104.             vertical = 0f;
    105.             }
    106.  
    107.          transform.Translate(0, vertical, 0);
    108.  
    109.  
    110.     }
    111.  
    112. }
    113.  

    I tried implementing a solution with the co-routine (see next code) and removing the "vertical = speed" and "vertical = -speed" from the initial jump (outside of the co-routine), the problem with it is that it makes the jump unresponsive, and only after 0.2 will the jump or double jump happen.

    Code (CSharp):
    1. IEnumerator SingleOrDoubleTap(string position)
    2.     {
    3.         yield return new WaitForSeconds(0.2f);    
    4.  
    5.         if (tapCount == 1)
    6.         {
    7.             Debug.Log("Follow tap : Double");
    8.             tapCount = 0;
    9.             jumpCount = 4;
    10.          
    11.         }
    12.  
    13.  
    14.         else if (tapCount == 2)
    15.         {  
    16.  
    17.              Debug.Log("Follow tap : Double");
    18.             tapCount = 0;
    19.             jumpCount = 8;                
    20.          
    21.        }
    22.  
    23.         if (position == "Top")
    24.         {
    25.             vertical = speed;
    26.         }
    27.         else if (position == "Bottom")
    28.         {
    29.             vertical = -speed;
    30.         }
    31.  
    32.     }

    I've thought of adding an interrumptjump bool if only one tap is pressed, and then do this :

    Code (CSharp):
    1. if (jumpCount == jumpLimit | (interrumptJump && jumpCount == jumpLimit / 2 ) )
    2.             {
    3.             vertical = 0f;
    4.             }
    5.  

    but it doesn't work, as the code seems to execute before the bool changes its value, so the jumpCount always reaches the jumpLimit and the jump goes to maximum.

    Nor does initializing jumpLimit in the co-routine work, because i need a JumpLimit already initialized to make the first jump quick enough and avoid the latency.

    I tried to make double tap leads to another jump, by manipulating the "vertical = speed" and jumpCount variables in the co-routine while keeping them in the first jump, but it works inconsistently and when it does it leads to a jump only after the first jump has stopped, just repeating two jumps like in the first video with a stop in between, vs the smooth i'm looking for like in the second video posted.

    Is there anyway, or does anybody have any hint on how to go at this, or any similar use-case i can learn from ?

    Thank you in advance.
     
    Last edited: Aug 23, 2023
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    Definitely don't use coroutines. They will not help this problem and in fact make it far harder to solve.

    When the first tap happens, zero a timer (just a
    float
    ) and zero a tap counter (just an
    int
    ).

    Then each subsequent tap of the button, check that timer to see if it is "fast enough" for you to consider a doublejump.

    Then you can use the time of that second tap to decide how much velocity to adjust the jump by.

    Here's some simple timer examples:

    Cooldown timers, gun bullet intervals, shot spacing, rate of fire:

    https://forum.unity.com/threads/fire-rate-issues.1026154/#post-6646297

    GunHeat (gunheat) spawning shooting rate of fire:

    https://forum.unity.com/threads/spawning-after-amount-of-time-without-spamming.1039618/#post-6729841
     
  3. gravesaad

    gravesaad

    Joined:
    Jul 7, 2023
    Posts:
    9
    I'm sorry, but i'm at loss in translating any of those solution to my case, when i do

    Code (CSharp):
    1.  
    2.  
    3. if (jumpHeat > 0)
    4.         {
    5.            jumpHeat -= Time.deltaTime;
    6.            
    7.          }
    8.  
    9.  if (Input.touchCount > 0)  // If player asked to jump
    10.         {
    11.  
    12.          
    13.             if (jumpHeat <= 0)
    14.             {
    15.  
    16.                 jumpHeat = 0.50f;
    17.                 Debug.Log("Jump");        
    18.               // Jump here                    
    19.              
    20.             }
    21.  
    22.             else
    23.             {
    24.                 Debug.Log("Double Jump");
    25.              
    26.             }        
    27.        
    28.                  
    29.         }
    It works perfectly for not initiating another jump before the timer resets, but whatever i put on the "else" executes with the if. I've tried with

    Code (CSharp):
    1.  else if (Input.touchCount > 0))
    2.             {
    3.                 Debug.Log("Debug : Double");              
    4.              
    5.             }
    and it doesn't work either.

    Similarily when putting the TapCounter either in the first or the second condition : In the first, it
    logicallycounts just the Jumps inside the interval, in the second one it keeps updating more than once.

    I also tried this to make either the if or the else executes, but it doesn't work either : /

    Code (CSharp):
    1. if (jumpHeat <= 0)
    2.             {
    3.  
    4.                 jumpHeat = 0.50f;
    5.                 Debug.Log("Jump");  
    6.                 pursueJump = true;                        
    7.              
    8.             }
    9.  
    10.             else if (pursueJump)
    11.             {
    12.                 Debug.Log("Double Jump");
    13.                pursueJump = false;
    14.              
    15.             }    
     
    Last edited: Aug 24, 2023