站在地面上
本课属于 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。
挑战
简单只有当玩家站在某个物体上时,才让它跳跃。
- 添加
private bool grounded;。在OnCollisionStay中,当collision.GetContact(0).normal.y > 0.5f时,将它设为 true;在OnCollisionExit中,将它设为 false。 - 在
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 在线编辑器