Menu
CoddyTech

Ground Check with a Ray

Part of the Physics and Gameplay section of Coddy's Unity journey. Lesson 35 of 63.

A jump should start only from the ground. Standing on the Ground worked that out from contact normals, kept up to date by collision messages. A ray answers "am I standing on something?" on the spot, at any moment: cast it straight down from the centre, a little longer than the distance from the centre to the bottom. This player is a capsule 2 units tall, so its bottom is 1 unit below its centre, and the ray is 1.1 long:

public float jumpForce = 5f;
private Rigidbody rb;

void Start()
{
    rb = GetComponent<Rigidbody>();
}

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space) && IsGrounded())
    {
        rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
    }
}

bool IsGrounded()
{
    return Physics.Raycast(transform.position, Vector3.down, 1.1f);
}

The extra 0.1 is a margin. A body resting on the floor can sit a hair above it or sink a hair into it, so a ray exactly 1 long misses on some frames. Much longer is wrong the other way: with 3, the player could jump again 2 units up in the air, and with no length at all the ray always finds the floor, so every press is a jump.

The ray starts inside the player's own collider, which rays skip, so it never reports the player. The key is read in Update(), because GetKeyDown is true for one frame only, and a one-off impulse can be added right there, as in Jump with an Impulse.

challenge icon

Challenge

Medium

The frog jumps whenever Space is pressed, even in mid-air, so it can climb into the sky. Fix Hopper so it jumps only from the ground:

  • Add a method bool IsGrounded() that casts a ray straight down from the frog's centre. The frog is a sphere scaled to 1.5, so its radius is 0.75: make the ray reach 0.1 past its bottom.
  • Jump only when Space is pressed and IsGrounded() is true.

Press Play and try to jump twice, then Check.

Try it yourself

using UnityEngine;

public class Hopper : MonoBehaviour
{
    public float jumpForce = 6f;
    private Rigidbody rb;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        }
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Physics and Gameplay