图层与 LayerMask
本课属于 Coddy Unity 学习旅程的“物理与游戏玩法”单元。第 38 课,共 71 课。
每个 GameObject 都位于一个层上,你可以在 Inspector 顶部的 Layer 菜单中选择该层。Unity 有 32 个层:其中一些是内置的(0 Default、2 Ignore Raycast、4 Water、5 UI),你可以在 Tags and Layers 中为自己的层命名,从 User Layer 3 开始。LayerMask 是一组层,每层对应一位。将它传给射线检测,放在 maxDistance 之后,射线就会忽略集合以外的层上的所有碰撞体。
这个玩家应该从地面起跳,而不是从敌人的头上起跳。将地板放到 Ground 层,并在脚本中添加一个 LayerMask 字段。Inspector 会将它显示为一个菜单,你可以在其中勾选 Ground:
[SerializeField] private LayerMask groundMask;
bool IsGrounded()
{
return Physics.Raycast(transform.position, Vector3.down, 1.1f, groundMask);
}只包含 Ground 的遮罩也能避免检测到玩家自身。射线会跳过它起点所在的碰撞体,但不会跳过玩家的其他碰撞体,例如子对象的碰撞体;后续课程中的重叠检测也会检测到玩家自身的碰撞体。因此,如果在脚边检测时不使用遮罩,结果就总会是已接地。将玩家及其子对象放到 Player 层,并在检测所用的遮罩中排除 Player。在代码中,LayerMask.GetMask("Ground", "Platform") 会根据层名称创建遮罩,而在遮罩前加上 ~ 会将其反转,使之包含原本不包含的所有层。
挑战
中等让侦察兵的射线看向自己的灯笼之外。
- 在
LookAhead()中,构建int mask = ~LayerMask.GetMask("Player");:包含除 Player 以外的所有图层,侦察兵和它的灯笼就在这些图层上。 - 将
mask传给射线检测,放在range后面。
按“开始”,然后用方向键转动侦察兵:控制台会显示 Rock 和 Tree。然后按“检查”。
亲手试试
using UnityEngine;
public class Spotter : MonoBehaviour
{
public float range = 10f;
private string last = "";
void Update()
{
string seen = LookAhead();
if (seen != last)
{
Debug.Log("Ahead: " + seen);
last = seen;
}
}
// 范围内前方第一个物体的名称,如果没有,则为 "nothing"。
public string LookAhead()
{
if (Physics.Raycast(transform.position, transform.forward, out RaycastHit hit, range))
{
return hit.collider.name;
}
return "nothing";
}
}
物理与游戏玩法中的所有课
自己练习: Unity 在线编辑器