Menu
CoddyTech

站在地面上

本课属于 Coddy Unity 学习旅程的“物理与游戏玩法”单元。第 11 课,共 71 课。

每个接触点都有一个 normal:它是一个长度为 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 中,当 collision.GetContact(0).normal.y > 0.5f 时,将它设为 true;在 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 在线编辑器