Tag & Layer
在 Unity 中,Tag 给 GameObject 贴上脚本识别标签(CompareTag);Layer 把对象分组,用于 Physics 碰撞矩阵、Camera Culling 与 Raycast。Tag 偏逻辑识别,Layer 偏物理与渲染过滤——正确配置 Collision Matrix,能让交互过滤清晰高效。
想象一下...
Tag 就像胸牌——“Player”“Enemy”“Treasure”——警卫一眼认出并立刻反应(CompareTag)。Layer 则像建筑里的分区平面图——员工只能进获准的楼层(Camera Culling Mask),房间也决定谁能和谁发生物理交互(Physics Layer Collision Matrix)。
概念详解
Tag 是挂在 GameObject 上的字符串标签(每个 GO
一个)。优先用 gameObject.CompareTag(“Player”),而不是
gameObject.tag == “Player”,以避免字符串分配。内置 Tag:
Untagged、Respawn、Finish、EditorOnly、MainCamera、Player、GameController。
Layer 是整数 0–31(最多 32 层)。每个 Layer 对应 LayerMask(32 位位掩码)中的一位。 Layer 驱动:(1) Camera Culling Mask——只渲染勾选的 Layer; (2) Physics Layer Collision Matrix——哪些 Layer 会碰撞; (3) Raycasting LayerMask——射线能打到哪些 Layer。
LayerMask:
LayerMask.GetMask(“Enemy”, “NPC”) 可组合多个层。用 ~ 取反
(排除):~LayerMask.GetMask(“Player”) = 除 Player 外的所有层。
良好实践:按职责命名 Layer(不要用对象名), 在 Edit → Project Settings → Tags and Layers 中创建。例如: Ground、Projectile、Interactable、UI、PostProcess。
对比:Tag 与 Layer
🏷 Tag
用途
在脚本中识别对象类型(CompareTag)
数量
无上限(字符串);每个 GO 只有 1 个 tag
应用
OnTriggerEnter、FindWithTag、脚本比较
示例
📚 Layer
用途
为 Physics 与 Camera 渲染分组对象
数量
最多 32 层(0–7 由 Unity 保留),位 0–31
应用
Culling Mask、Collision Matrix、Raycast LayerMask
示例
动手步骤
创建新的 Tag/Layer
Edit → Project Settings → Tags and Layers。在 Tags 或 Layers 列表中添加条目。
在 GameObject 上指定
在 Hierarchy 选中 GO → Inspector → 顶部的 Tag 或 Layer 下拉框。
配置 Collision Matrix
Edit → Project Settings → Physics → Layer Collision Matrix → 取消勾选不应碰撞的层对。
设置 Camera Culling Mask
选中 Camera → Inspector → Culling Mask → 勾选要渲染的 Layer(UI Camera 通常只渲 UI)。
在 Raycast 中使用 LayerMask
Physics.Raycast(origin, dir, distance, LayerMask.GetMask("Ground")) —— 只命中 Ground。
交互模拟器
点击 GameObject 选中。修改 Tag 和 Layer。查看 Collision Matrix,并尝试 Raycast。
Hierarchy
选择一个 GameObject
代码示例
基础在 OnTriggerEnter 中用 Tag 识别对象。
using UnityEngine;
public class TreasureChest : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
// CompareTag does not allocate a string — better than ==
if (other.CompareTag("Player"))
{
Debug.Log("Player collected the treasure chest!");
gameObject.SetActive(false);
}
}
}
// Find every Enemy in the scene by Tag
GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
foreach (var e in enemies) e.GetComponent<EnemyAI>().Alert();代码示例
进阶Raycast 中的 LayerMask,以及运行时切换 Layer。
using UnityEngine;
public class PlayerGroundCheck : MonoBehaviour
{
[SerializeField] private float checkDistance = 0.1f;
// Build LayerMask from names — cache it, do not rebuild every frame
private readonly int _groundMask = LayerMask.GetMask("Ground", "Platform");
public bool IsGrounded =>
Physics.Raycast(transform.position, Vector3.down, checkDistance, _groundMask);
void Update()
{
if (IsGrounded)
GetComponent<Rigidbody>().drag = 5f; // friction while grounded
else
GetComponent<Rigidbody>().drag = 0f; // no drag in the air
}
// Change Layer at runtime (e.g. ghost through walls)
public void SetGhostMode(bool ghost)
{
gameObject.layer = LayerMask.NameToLayer(ghost ? "Ghost" : "Player");
}
}📌 快速记忆
- ▸Tag = 脚本中识别;Layer = 控制 Physics 与 Camera
- ▸优先用
CompareTag(),避免tag ==产生 GC - ▸LayerMask 是位掩码——用
GetMask(),别写魔法数字 - ▸最多 32 个 Layer;Collision Matrix 里关掉不需要的碰撞对
⚠️ 常见错误
❌ 使用 gameObject.tag == "Player"
每次调用都分配字符串 → GC 压力
✅ gameObject.CompareTag("Player")
❌ 硬编码层位:layerMask = 8
Layer 顺序一变就坏
✅ LayerMask.GetMask("Ground")