Search code examples
c#unity-game-engineraycasting

"isGrounded" variable doesn't change to false after initial jump in Unity


Overview

Using Unity2D 2019.3.5, I am making a platformer game using C#. I implemented raycast to detect when my player is touching the ground and attempted to make it only so the player can jump only once.

Problem

Although I thought I programmed my character to jump once, after the first jump, the Unity engine still shows a checkmark to my "isGrounded" variable and only turns to false (unchecked) after a second jump before hitting the ground.

My Code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player_Controller : MonoBehaviour
{

    public int playerSpeed = 10;
    public int playerJumpPower = 1250;
    private float moveX;
    public bool isGrounded;
    public float distanceToBottomOfPlayer = .7f;

    // Update is called once per frame
    void Update()
    {
        PlayerMove();
        PlayerRaycast();
    }

    void PlayerMove()
    {
        // CONTROLS
        moveX = Input.GetAxis("Horizontal");
        if (Input.GetButtonDown("Jump") && isGrounded == true)
        {
            Jump();
        }

        // ANIMATIONS

        // PLAYER DIRECTION
        if (moveX < 0.0f)
        {
            GetComponent<SpriteRenderer>().flipX = true;
        }
        else if (moveX > 0.0f)
        {
            GetComponent<SpriteRenderer>().flipX = false;
        }

        // PHYSICS
        gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(moveX * playerSpeed, 
gameObject.GetComponent<Rigidbody2D>().velocity.y);
    }

    void Jump()
    {
        GetComponent<Rigidbody2D>().AddForce(Vector2.up * playerJumpPower);
        isGrounded = false;
    }

    void PlayerRaycast()
    {
        // Ray Down
        RaycastHit2D rayDown = Physics2D.Raycast(transform.position, Vector2.down);

        if (rayDown.collider != null && rayDown.distance < distanceToBottomOfPlayer && 
rayDown.collider.tag == "ground")
        {
            isGrounded = true;
        }
    }
}

Extra Info

I did have to change a Unity setting in Edit > Project Settings > Physics 2D > Queries Start In Colliders. I had to turn this setting off (uncheck) in order to get my player to jump using the code I wrote above. I know there are other ways of making my player jump, however, this seemed to be the most efficient while maintaining the readability of the code.

Solutions Tried

What I believe the problem is that I have a raycast issue that I don't know how to fix. I looked at other Stack Overflow posts including the ones recommended after writing this post, but none of them applied to my problem.

Final Notes

As I said before, I know there are other ways to make my player jump only once using different code, however, I would like to stick with this code for my own learning purposes and for future reference.


Solution

  • Because you can't be sure that isGrounded is false when you call Jump().
    I think issue lies there.
    Try not setting isGrounded flag when calling Jump(). Setting isGrounded is purely PlayerRaycast()'s job.

        void Update()
        {
            // Raycast before moving
            PlayerRaycast();
            PlayerMove();
        }
    
         void PlayerRaycast()
        {
            // Ray Down
            RaycastHit2D rayDown = Physics2D.Raycast(transform.position, Vector2.down);
    
            if (rayDown.collider != null && rayDown.collider.tag == "ground")
            {
                if( rayDown.distance < distanceToBottomOfPlayer )
                {
                    isGrounded = true;
                }
                else
                {
                    isGrounded = false;
                }
            }
        }
    
        void Jump()
        {
            GetComponent<Rigidbody2D>().AddForce(Vector2.up * playerJumpPower);
            //isGrounded = false;
        }