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
EasyThe 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
groundedis 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;
}
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Physics and Gameplay
1Rigidbody
Gravity and MassPush with AddForceJump with an ImpulseFixedUpdate for PhysicsVelocityKinematic BodiesRecap: Launch Pad2Collisions
OnCollisionEnterWhat Did I Hit?Break on ImpactStanding on the GroundBounce and FrictionCollider ShapesRecap: Breakable Wall