Menu
CoddyTech

Standing on the Ground

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

Every contact has a normal: a direction of length 1, perpendicular to the surface you touched, pointing away from it toward your object. collision.GetContact(0) is the first point of contact, and its normal tells you which side you touched. Standing on flat ground it is (0, 1, 0); against a wall on your right it is (-1, 0, 0); bumping your head on a ceiling it is (0, -1, 0).

This crate tells landings from side bumps:

void OnCollisionEnter(Collision collision)
{
    Vector3 normal = collision.GetContact(0).normal;
    if (normal.y > 0.5f)
    {
        Debug.Log("Landed on " + collision.gameObject.name);
    }
    else
    {
        Debug.Log("Bumped the side of " + collision.gameObject.name);
    }
}

The test is normal.y > 0.5f rather than exactly 1 so that slopes count as ground too: y is 0.5 on a 60 degree slope, steeper than anyone walks up. Two more messages help with anything that lasts: OnCollisionStay runs on every physics step while the contact lasts, and OnCollisionExit once when it ends. An exit has no contact points, since nothing is touching any more, so do not call GetContact there.

challenge icon

Challenge

Easy

The player can walk and jump, but Space works in mid-air too, so it can climb the sky one jump at a time, and jump off the side of the wall. (Its collider has a frictionless material, so it slides down walls instead of sticking to them.) Make it jump only while it stands on something.

  • Keep a bool grounded: true while the player touches something whose contact normal points up (y above 0.5), false once it stops touching.
  • Jump only when Space was pressed and grounded is true. A press in the air is ignored, not saved for the landing.

Press Play, try to jump twice and to climb the wall, then Check.

Try it yourself

using UnityEngine;

public class Hopper : MonoBehaviour
{
    public float speed = 4f;
    public float jump = 6f;
    private Rigidbody rb;
    private bool jumpPressed;

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

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            jumpPressed = true;
        }
    }

    void FixedUpdate()
    {
        float h = Input.GetAxisRaw("Horizontal");
        rb.linearVelocity = new Vector3(h * speed, rb.linearVelocity.y, 0);
        if (jumpPressed)
        {
            rb.AddForce(Vector3.up * jump, ForceMode.Impulse);
            jumpPressed = false;
        }
    }
}
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