Menu
CoddyTech

图层与 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") 会根据层名称创建遮罩,而在遮罩前加上 ~ 会将其反转,使之包含原本不包含的所有层。

challenge icon

挑战

中等

让侦察兵的射线看向自己的灯笼之外。

  1. 在 LookAhead() 中,构建 int mask = ~LayerMask.GetMask("Player");:包含除 Player 以外的所有图层,侦察兵和它的灯笼就在这些图层上。
  2. 将 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 在线编辑器