Reputation: 1
I'm working on a Unity project for a certification course, putting together a infinite runner game. In order to constrain the player's jump so that they can only jump when on the ground, I created a raycast that shoots from the player's feet for an extremely short distance - if the raycast detects something, then the player is considered 'grounded' and is allowed to jump, otherwise they are in the air and cannot jump. Simple stuff.
But when the player runs off a platform without jumping, the raycast still registers as hitting a collider without any colliders below it, allowing the player to jump in mid-air. This isn't just a moment of Coyote Time or anything, the raycast stays detecting a collider all the way until the player is over another platform, at which point it stops detecting anything beneath the player. I have no idea what's causing this - the platforms' colliders do not extend beyond their visuals, so as far as I can tell there is nothing there for the raycast to be detecting. What's going on, and how can I fix it?
Here is my code for jumping and the raycast:
public class Player : MonoBehaviour
{
[SerializeField] Rigidbody2D rb;
[SerializeField] float jumpForce = 5.0f;
[SerializeField] Transform raycastOrigin;
[SerializeField] bool isGrounded;
void Update()
{
if (isGrounded == true)
{
Debug.DrawRay(raycastOrigin.position, Vector2.down, Color.green);
if (Input.GetKeyDown(KeyCode.Space))
{
rb.AddForce(new Vector2(0, jumpForce), ForceMode2D.Impulse);
}
} else
{
Debug.DrawRay(raycastOrigin.position, Vector2.down, Color.red);
}
RaycastHit2D hit = Physics2D.Raycast(raycastOrigin.position, Vector2.down); //Shoot a raycast down to tell if the player is on the ground.
if(hit.collider != null) // check if the Raycast is hitting anything
{
if (hit.distance < 0.01f) // If the thing the raycast has hit is really close to the origin
{
isGrounded = true;
} else {
isGrounded = false;
}
Debug.Log(hit.transform.name);
}
}
}
Here is a video of the issue in action.
I've tried moving the collider, tinkering with the platform collisions, and reducing the raycast's hit distance, but nothing seems to have changed. I also tried rewriting the if statements, but the ones listed here produce the best results save for this one issue.
Upvotes: 0
Views: 36
Reputation: 90813
Despite what you already figured out yourself about the missing else
case you could combine these to make your code way less complex
isGrounded = hit.collider != null && hit.distance < 0.01f;
An alternative to a raycast might be Physics2D.OverlapCircleNonAlloc
as you are not interested in the exact result, only whether there is a hit at all
private static readonly Collider2D[] hits = new Collider2D[1];
public LayerMask groundLayers;
...
isGrounded = Physics2D.OverlapCircleNonAlloc(raycastOrigin.position, 0.01f, hits, groundLayers) == 1;
Upvotes: 1
Reputation: 1
I fixed the issue, and I'll leave up the answer if anyone in the future has this same problem: I simply added an else statement after the if(hit.collider != null) statement that sets isGrounded to false. That way, if the raycast is not detecting anything, grounded is false. Simple issue, simple fix. The if statement looks like this now:
if(hit.collider != null) // check if the Raycast is hitting anything
{
if (hit.distance < 0.01f) // If the thing the raycast has hit is really close to the origin
{
isGrounded = true;
} else {
isGrounded = false;
}
Debug.Log(hit.transform.name);
} else
{
isGrounded = false;
}
Upvotes: 0