Standing on the Ground
Part of the Physics and Gameplay section of Coddy's Unity journey. Lesson 11 of 71.
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
EasyLet the player jump only while it stands on something.
- Add
private bool grounded;. InOnCollisionStay, set it true whencollision.GetContact(0).normal.y > 0.5f; inOnCollisionExit, set it false. - In
FixedUpdate(), jump onlyif (jumpPressed && grounded), and setjumpPressed = false;after thatif, so a press in the air is dropped.
Press Play and try a double jump: the second press does nothing. 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;
}
}
}
All lessons in Physics and Gameplay
1Rigidbody
Gravity and MassPush with AddForceJump with an ImpulseFixedUpdate for PhysicsVelocityKinematic BodiesRecap: Launch Pad4Coroutines
InvokeInvokeRepeating, CancelInvokeYour First CoroutineLoops in CoroutinesStopping CoroutinesRecap: Countdown10Project: Arena Escape
The ArenaHunters2Collisions
OnCollisionEnterWhat Did I Hit?Break on ImpactStanding on the GroundBounce and FrictionCollider ShapesRecap: Breakable WallPractice on your own: Unity playground