0
\$\begingroup\$

Unity Version: 2017.4.1f1

I currently have a game with a jumping mechanic. I only want the jump to work where you're on ground, so I have planes on top of everything, which, if you are on a plane, then you can jump.

This works, however if you are in a position where you are falling and then in quick succession, hit one plane, fall off that plane (like when your centre of mass is hanging off the edge), then land on another plane, at the end of it all, it still thinks you are on the air.

Note: I don't think this is an error with the velocity of the player, at no point do you go through a collider.

So my question is, is there an error in my code (shown below) which I can fix, or should I take another approach towards jumping, thanks. Relevant code below.

private bool canJump;
private Rigidbody rb;
public float jumpStrength;

private void OnCollisionEnter(Collision collision)
{
    if (collision.collider.CompareTag("Jumpable"))
    {
        canJump = true;
    }
}
private void OnCollisionExit(Collision collision)
{
    if (collision.collider.CompareTag("Jumpable"))
    {
        canJump = false;
    }
}
private void Update()
{
    if (canJump && Input.GetKey(Keyode.W))
    {
        rb.velocity += new Vector3(0, jumpStrength, 0);
        canJump = false; // Safety measure to ensure consistent jump height
    }
}

Thanks

\$\endgroup\$
  • \$\begingroup\$ Which version of Unity are you using? Looks like 2017.x which is different from 2018.x, just want to make sure we clarify. \$\endgroup\$ – Stephan Jul 12 '18 at 18:05
  • \$\begingroup\$ 2017.4.1f1. Edited main post. \$\endgroup\$ – Devintage Jul 12 '18 at 18:23
1
\$\begingroup\$

I agree with LinkWindcrafter that a raycast (or larger shapecast) is more likely what you'll want here.

But, if you want to keep using your toggle style, you can rescue it with a small change:

private int jumpableCount;
private bool canJump {
    get { return jumpableCount > 0; }
}

private void OnCollisionEnter(Collision collision)
{
    if (collision.collider.CompareTag("Jumpable"))
        jumpableCount++;
}
private void OnCollisionExit(Collision collision)
{
    if (collision.collider.CompareTag("Jumpable"))
        jumpableCount--;
}

This way if you touch JumpableA (jumpableCount = 1) then touch JumpableB (jumpableCount = 2) and then stop touching JumpableA (jumpableCount = 1), canJump is still true, because it knows this CollisionExit wasn't your last remaining Jumpable in reach.

\$\endgroup\$
1
\$\begingroup\$

It is possible that you have lots of planes on the ground, so you may have entered a plane, and have the flag as true, but you could have also left another plane trigger, even when you were grounded, so it will overwrite the flag to false.

To check ground, a Raycast is almost always used, you could try something like this:

private bool canJump;
private Rigidbody rb;
public float jumpStrength;
public float rayLength;

/*private void OnCollisionEnter(Collision collision)
{
    if (collision.collider.CompareTag("Jumpable"))
    {
        canJump = true;
    }
}
private void OnCollisionExit(Collision collision)
{
    if (collision.collider.CompareTag("Jumpable"))
    {
        canJump = false;
    }
}*/

private bool IsGrounded()
{
    RaycastHit hit;

    if(Physics.Raycast(transform.position, Vector3.down, out hit, rayLength))
    {
        if(hit.transform.CompareTag("Jumpable")) return true;
    }

    return false;
}

private void Update()
{
    canJump = IsGrounded();
    if (canJump && Input.GetKey(Keyode.W))
    {
        rb.velocity += new Vector3(0, jumpStrength, 0);
        canJump = false; // Safety measure to ensure consistent jump height
    }
}

The Physics.Raycast method has a lot of overloads, the one I provided is a basic one. I personally recommend passing LayerMasks as parameter, so you can just detect certain objects with certain layers (example, you could make all your jumpable planes have a custom "Jumpable" layer and pass it as parameter).

hope it helps.

\$\endgroup\$
  • \$\begingroup\$ Went to bed last night and I couldn't believe I hadn't thought that was the problem. Unfortunately I can't use raycasts because the character is a rotating cube and I can be put into a position where my lowest point is below a platform, a higher point above, but not be touching the edge, and still be able to jump. It helped though! \$\endgroup\$ – Devintage Jul 13 '18 at 6:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.