Menu
CoddyTech

Стояние на земле

Часть раздела Физика и игровой процесс путешествия по Unity на Coddy. Урок 11 из 71.

У каждого контакта есть нормаль: направление длиной 1, перпендикулярное поверхности, которой вы коснулись и направленное от неё к вашему объекту. collision.GetContact(0) — это первая точка контакта, а её normal показывает, какой стороны вы коснулись. На ровной поверхности нормаль равна (0, 1, 0); если справа от вас стена — (-1, 0, 0); если вы ударились головой о потолок — (0, -1, 0).

Этот фрагмент кода отличает приземление от бокового столкновения:

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);
    }
}

Проверка использует normal.y > 0.5f, а не точное значение 1, чтобы наклонные поверхности тоже считались землёй: на склоне с углом 60 градусов значение y равно 0.5, а по таким крутым склонам никто не ходит. Ещё два сообщения пригодятся для всего, что длится какое-то время: OnCollisionStay выполняется на каждом шаге физики, пока длится контакт, а OnCollisionExit — один раз, когда контакт заканчивается. У события выхода нет точек контакта, поскольку больше ничего не соприкасается, поэтому не вызывайте там GetContact.

challenge icon

Задание

Легко

Разрешите игроку прыгать, только когда он стоит на чём-либо.

  1. Добавьте private bool grounded;. В OnCollisionStay задайте ему значение true, когда collision.GetContact(0).normal.y > 0.5f; в OnCollisionExit задайте значение false.
  2. В FixedUpdate() выполняйте прыжок, только если if (jumpPressed && grounded), а после этого if установите jumpPressed = false;, чтобы нажатие в воздухе пропускалось.

Нажмите «Играть» и попробуйте выполнить двойной прыжок: второе нажатие ничего не делает. Затем нажмите «Проверить».

Попробуйте сами

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;
        }
    }
}

Все уроки раздела Физика и игровой процесс

Потренируйтесь самостоятельно: Песочница Unity