Why when pressing on the space key to jump twice in a row the player is jumping again ?

       public bool useCharacterForward = false;
       public bool lockToCameraForward = false;
       public float turnSpeed = 10f;
       public KeyCode sprintJoystick = KeyCode.JoystickButton2;
       public KeyCode sprintKeyboard = KeyCode.Space;
       public bool useJump = false;
       public Vector3 jump;
       public float jumpImpulse;

       private float turnSpeedMultiplier;
       private float speed = 0f;
       private float direction = 0f;
       private bool isSprinting = false;
       private Animator anim;
       private Vector3 targetDirection;
       private Vector2 input;
       private Quaternion freeRotation;
       private Camera mainCamera;
       private float velocity;
       private bool isGrounded;
       private Rigidbody rb;

       // Use this for initialization
       void Start()
       {
           anim = GetComponent<Animator>();
           mainCamera = Camera.main;
           rb = GetComponent<Rigidbody>();
           jump = new Vector3(0.0f, 2.0f, 0.0f);
       }

       private void OnCollisionStay(Collision collision)
       {
           if (collision.gameObject.tag == "Ground")
           {
               isGrounded = true;
           }
       }

       private void Update()
       {
           if (Input.GetKeyDown(KeyCode.Space) && isGrounded && useJump)
           {
               rb.AddForce(jump * jumpImpulse, ForceMode.Impulse);
               isGrounded = false;
           }
       }

Even if the player is in the air and the even if I’m checking for the ground tag I can still press on space once more while the player is in the air after jumping and it will make a jump and move the player higher in the air.

but I’m setting the isGround to false and the player is much higher above the ground and still pressing space make it jumping in the air while in the air already.

This screenshot show how the ground object is built in the hierarchy. The player have a capsule collider and a rigidbody.

There are 3 floor objects :

I tried this way :

private void OnCollisionStay(Collision collision)
        {
            if (isGrounded == false)
            {
                isGrounded = true;
            }
        }

I tried this :

private void OnCollisionStay(Collision collision)
        {
            isGrounded = collision.gameObject.tag == "Ground";
        }

Still while the player is already in the air after the first jumping I can press space again and the player will jump again and get higher.

The full script : The jumping part is in the Update()

using UnityEngine;

    public class MovementTesting : MonoBehaviour
    {
        public bool useCharacterForward = false;
        public bool lockToCameraForward = false;
        public float turnSpeed = 10f;
        public KeyCode sprintJoystick = KeyCode.JoystickButton2;
        public KeyCode sprintKeyboard = KeyCode.Space;
        public bool useJump = false;
        public Vector3 jump;
        public float jumpImpulse;

        private float turnSpeedMultiplier;
        private float speed = 0f;
        private float direction = 0f;
        private bool isSprinting = false;
        private Animator anim;
        private Vector3 targetDirection;
        private Vector2 input;
        private Quaternion freeRotation;
        private Camera mainCamera;
        private float velocity;
        private bool isGrounded;
        private Rigidbody rb;

        // Use this for initialization
        void Start()
        {
            anim = GetComponent<Animator>();
            mainCamera = Camera.main;
            rb = GetComponent<Rigidbody>();
            jump = new Vector3(0.0f, 2.0f, 0.0f);
        }

        private void OnCollisionStay(Collision collision)
        {
            isGrounded = collision.gameObject.tag == "Ground";
        }

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space) && isGrounded && useJump)
            {
                rb.AddForce(jump * jumpImpulse, ForceMode.Impulse);
                isGrounded = false;
            }
        }

        // Update is called once per frame
        void FixedUpdate()
        {
            input.x = Input.GetAxis("Horizontal");
            input.y = Input.GetAxis("Vertical");

            // set speed to both vertical and horizontal inputs
            if (useCharacterForward)
                speed = Mathf.Abs(input.x) + input.y;
            else
                speed = Mathf.Abs(input.x) + Mathf.Abs(input.y);

            speed = Mathf.Clamp(speed, 0f, 1f);
            speed = Mathf.SmoothDamp(anim.GetFloat("Speed"), speed, ref velocity, 0.1f);
            anim.SetFloat("Speed", speed);

            if (input.y < 0f && useCharacterForward)
                direction = input.y;
            else
                direction = 0f;

            anim.SetFloat("Direction", direction);

            // set sprinting
            isSprinting = ((Input.GetKey(sprintJoystick) ||
                Input.GetKey(sprintKeyboard)) && 
                input != Vector2.zero && direction >= 0f && useJump == false);
            anim.SetBool("isSprinting", isSprinting);

            // Update target direction relative to the camera view (or not if the Keep Direction option is checked)
            UpdateTargetDirection();
            if (input != Vector2.zero && targetDirection.magnitude > 0.1f)
            {
                Vector3 lookDirection = targetDirection.normalized;
                freeRotation = Quaternion.LookRotation(lookDirection, transform.up);
                var diferenceRotation = freeRotation.eulerAngles.y - transform.eulerAngles.y;
                var eulerY = transform.eulerAngles.y;

                if (diferenceRotation < 0 || diferenceRotation > 0) eulerY = freeRotation.eulerAngles.y;
                var euler = new Vector3(0, eulerY, 0);

                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(euler), turnSpeed * turnSpeedMultiplier * Time.deltaTime);
            }
        }

        public virtual void UpdateTargetDirection()
        {
            if (!useCharacterForward)
            {
                turnSpeedMultiplier = 1f;
                var forward = mainCamera.transform.TransformDirection(Vector3.forward);
                forward.y = 0;

                //get the right-facing direction of the referenceTransform
                var right = mainCamera.transform.TransformDirection(Vector3.right);

                // determine the direction the player will face based on input and the referenceTransform's right and forward directions
                targetDirection = input.x * right + input.y * forward;
            }
            else
            {
                turnSpeedMultiplier = 0.2f;
                var forward = transform.TransformDirection(Vector3.forward);
                forward.y = 0;

                //get the right-facing direction of the referenceTransform
                var right = transform.TransformDirection(Vector3.right);
                targetDirection = input.x * right + Mathf.Abs(input.y) * forward;
            }
        }
    }

Hey!
I believe that what happens is that you press spacebar to jump and set isGrounded = true but the OnCollisionStay runs one more time and resets the isGrounded = true just before the connection between colliders is broken. This can because OnCollisionStay runs constantly.

Unless you want a double jump mechanic the easiest way to fix it would probably be to check:

if (rb.velocity.y < 0 && gameobject.CompareTag("Ground"))
    isGrounded = true;

The thinking I would suggest is to split the jumping process into STATES. Basically when you are jumping up (moving upwards) you do not necessarily want to check if you are grounded. You only want to do it when you are falling back down - when rb.velocity.y < 0.

I hope it will help!

1 Like

As much as you claim you are checking for the ground, it does not look like it based on what you have selected in your picture. You have selected an entire mesh using a mesh collider, meaning the entire model is considered the ground tag. Even if you are colliding with the wall of the mesh, the wall being part of the mesh is tagged as ground, so the player while colliding with the wall is still colliding with the ground according to your script.

Test your jump on a box or flat plane with the ground tag and see if it still happens. Also you should not need the “useJump” boolean as long as you are not intending for something like double-jump.

1 Like

If I’m doing it like this :

private void Update()
        {
            if (useJump && Input.GetKeyDown(KeyCode.Space))
            {
                if(rb.velocity.x < 0)
                {
                    rb.AddForce(jump * jumpImpulse, ForceMode.Impulse);
                }
            }
        }

It’s taking a lot of time between the times I can jump again. it’s taking time until the x is below 0 again.
Once pressing the spacebar key I have to wait like 5 seconds or so to be able to jump again.

Why are you checking x (left/right generally) to decide if you can jump? That seems wrong.

Either way, you must find a way to get the information you need in order to reason about what the problem is.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

If you would prefer something more full-featured here is a super-basic starter prototype FPS based on Character Controller (BasicFPCC):

https://discussions.unity.com/t/855344

Oh sorry for the typo! I meant Y value for the up axis.