Search Unity

Question Fixing Double Jump?

Discussion in 'Scripting' started by ChronoSynth, Jun 30, 2021.

  1. ChronoSynth

    ChronoSynth

    Joined:
    Nov 20, 2020
    Posts:
    36
    For my game, I have implemented a jump counter that counts how many times a player can jump before they have to return to the ground. The counter is supposed to reset once the player is grounded again. However, the counter resets every time I press the jump button, resulting in the character being able to triple jump instead of double jump like I expected. (If the character falls off a ledge before jumping, the counter behaves as expected.) I think what's happening is that my ground detection system switches the "isGrounded" variable to false when the character jumps, switches it to true a split second later, and back to false a split second after that. How do I counteract this?
    Here is the code for my player controller:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5. using UnityEngine.UI;
    6.  
    7. public class PlayerBehavior : MonoBehaviour
    8. {
    9.     float movementValue = 0f;
    10.     [SerializeField] float maxSpeed = 10f;
    11.     public Rigidbody2D rb;
    12.     CapsuleCollider2D playerCollider;
    13.     GroundCheck groundCheck;
    14.     [SerializeField] float jumpForce = 125f;
    15.     [SerializeField] float airControl = 5f;
    16.     [SerializeField] float dodgeForce = 10f;
    17.     [SerializeField] bool dodged = false;
    18.     public float decceleration = 1f;
    19.     bool isGrounded;
    20.     bool isMoving;
    21.     enum MovementCodeOptions { Default, Simple, Alternate };
    22.     [SerializeField] MovementCodeOptions movementCode = MovementCodeOptions.Default;
    23.     bool isFacingRight = true;
    24.     [SerializeField] int jumpCounter = 2;
    25.     bool canMove = true;
    26.     private void Awake()
    27.     {
    28.         rb = gameObject.GetComponent<Rigidbody2D>();
    29.         playerCollider = gameObject.GetComponent<CapsuleCollider2D>();
    30.         groundCheck = transform.Find("GroundCheck").GetComponent<GroundCheck>();
    31.     }
    32.  
    33.     private void FixedUpdate()
    34.     {
    35.         Vector3 debugEndPos = transform.position;
    36.         if (groundCheck.isGrounded)
    37.         {
    38.             isGrounded = true;
    39.             if (jumpCounter < 2)
    40.                 jumpCounter = 2;
    41.             Debug.Log("Player is grounded");
    42.         }
    43.         else
    44.         {
    45.             isGrounded = false;
    46.         }
    47.         if (movementValue != 0f && canMove)
    48.         {
    49.             rb.velocity = new Vector2(movementValue * maxSpeed, rb.velocity.y);
    50.         }
    51.         else
    52.         {
    53.             rb.velocity = new Vector2(Mathf.MoveTowards(rb.velocity.x, 0f, decceleration * Time.deltaTime), rb.velocity.y);
    54.         }
    55.        
    56.         if (movementValue == 0)
    57.         {
    58.             dodged = false;
    59.         }
    60.         if (movementValue < 0 && isFacingRight)
    61.             Flip();
    62.         else if (movementValue > 0 && !isFacingRight)
    63.             Flip();
    64.  
    65.         /*if (rb.velocity.magnitude < maxSpeed)
    66.         {
    67.             rb.AddForce(new Vector2(movementValue * acceleration * Time.deltaTime * 50f, rb.velocity.y));
    68.         }*/
    69.     }
    70.  
    71.     void OnMove(InputValue value)
    72.     {
    73.         movementValue = value.Get<float>();
    74.     }
    75.  
    76.     public void Flip()
    77.     {
    78.         isFacingRight = !isFacingRight;
    79.         transform.localScale = new Vector3(transform.localScale.x * -1, transform.localScale.y, transform.localScale.z);
    80.     }
    81.  
    82.     void OnJump()
    83.     {
    84.         if (jumpCounter > 0)
    85.         {
    86.             //rb.AddForce(new Vector2(rb.velocity.x, jumpForce), ForceMode2D.Impulse);
    87.             //rb.velocity = new Vector2(rb.velocity.x, jumpForce);
    88.             rb.velocity = Vector2.up * jumpForce;
    89.             jumpCounter -= 1;
    90.         }
    91.     }
    92.  
    93.     void OnBlock()
    94.     {
    95.         canMove = !canMove;
    96.     }
    97.     void OnDodge()
    98.     {
    99.         if (!dodged)
    100.         {
    101.             if (movementValue == 0)
    102.             {
    103.  
    104.             }
    105.             else if (movementValue > 0)
    106.             {
    107.                 rb.velocity = new Vector2(dodgeForce, 0f);
    108.             }
    109.             else
    110.             {
    111.                 rb.velocity = new Vector2(-dodgeForce, 0f);
    112.             }
    113.             dodged = true;
    114.         }
    115.     }
    116.  
    117. }
    118.  
    And here is the code for my ground detection system:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GroundCheck : MonoBehaviour
    6. {
    7.     public bool isGrounded;
    8.  
    9.     private void OnCollisionEnter2D(Collision2D collision)
    10.     {
    11.         isGrounded = collision != null && (((1 << collision.gameObject.layer) & LayerMask.GetMask("Ground")) != 0);
    12.     }
    13.  
    14.     private void OnCollisionExit2D(Collision2D collision)
    15.     {
    16.         isGrounded = false;
    17.     }
    18. }
    19.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    Whoa: EDIT: why are you copying
    IsGrounded
    over... don't do that!! That's mass confusion, cats living with dogs, etc.

    Use the value in place over on your groundCheck instance, ideally in a read-only capacity, but if you MUST clear it upon jumping, make a method to clear it.
     
  4. ChronoSynth

    ChronoSynth

    Joined:
    Nov 20, 2020
    Posts:
    36
    How do I do that? (Where am I doing it wrong?)

    EDIT: Before I made this post, by the way, I made it so that the jump counter resets every time the player's vertical velocity is zero, and it worked. Now, I just want to know where my initial mistake was and how to create your solution.
     
    Last edited: Jul 1, 2021
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    That might be just fine! Make sure you can still jump again if you're running on a ramp or uneven ground.

    My idea would basically be, instead of ALWAYS triggering Grounded when the flags are right and you hit something, ONLY do it if velocity is not positive (or not positive enough):

    Code (csharp):
    1. if (rb.velocity.y <= 0.01f)
    2. {
    3.   IsGrounded = true;
    4. }
    Another way would be to implement a dwell timer, where you need to be on the ground for a short period of time before it considers you on the ground. It can get a little bit fiddly... I would not have a separate ground checker, since ground checking is so integral to the main controller behavior.