Tag & Layer
Tags label GameObjects for script identification (CompareTag); Layers group objects for Physics collisions, Camera culling, and Raycast LayerMasks in Unity.
Imagine...
A Tag is like a name badge — "Player", "Enemy", "Treasure" — so a guard can recognize and react immediately (CompareTag). A Layer is like a zoned floor plan in a building — staff only enter floors they are cleared for (Camera Culling Mask), and rooms decide which rooms may physically interact (Physics Layer Collision Matrix).
The concept in detail
A Tag is a string label on a GameObject (one tag
per GO). Prefer gameObject.CompareTag(“Player”) over
gameObject.tag == “Player” to avoid string allocations. Built-in tags:
Untagged, Respawn, Finish, EditorOnly, MainCamera, Player, GameController.
A Layer is an integer 0–31 (32 layers max). Each Layer is one bit in a LayerMask (32-bit bitmask). Layers drive: (1) Camera Culling Mask — only selected Layers render; (2) Physics Layer Collision Matrix — which Layers collide; (3) Raycasting LayerMask — which Layers a ray can hit.
LayerMask:
LayerMask.GetMask(“Enemy”, “NPC”) combines layers. Use ~ to
invert (exclude): ~LayerMask.GetMask(“Player”) = every layer except Player.
Good practice: name Layers by role (not object names), created under Edit → Project Settings → Tags and Layers. Examples: Ground, Projectile, Interactable, UI, PostProcess.
Compare: Tag vs Layer
🏷 Tag
Purpose
Identify object type in scripts (CompareTag)
Quantity
Unlimited (string); each GO has exactly 1 tag
Uses
OnTriggerEnter, FindWithTag, script comparisons
Examples
📚 Layer
Purpose
Group objects for Physics & Camera rendering
Quantity
Max 32 layers (0–7 reserved by Unity), bits 0–31
Uses
Culling Mask, Collision Matrix, Raycast LayerMask
Examples
Hands-on steps
Create a new Tag/Layer
Edit → Project Settings → Tags and Layers. Add entries to the Tags or Layers list.
Assign on a GameObject
Select the GO in Hierarchy → Inspector → Tag or Layer dropdown at the top.
Configure the Collision Matrix
Edit → Project Settings → Physics → Layer Collision Matrix → uncheck pairs that should not collide.
Set Camera Culling Mask
Select Camera → Inspector → Culling Mask → pick Layers to render (a UI Camera often only renders UI).
Use LayerMask in Raycast
Physics.Raycast(origin, dir, distance, LayerMask.GetMask("Ground")) — only hits Ground.
Interactive simulator
Click a GameObject to select it. Change Tag and Layer. Inspect the Collision Matrix and try a Raycast.
Hierarchy
Select a GameObject
Code example
BasicIdentify objects with Tag inside OnTriggerEnter.
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();Code example
AdvancedLayerMask in Raycast and changing layer at runtime.
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");
}
}📌 Quick recap
- ▸Tag = identify in scripts; Layer = control Physics and Camera
- ▸Prefer
CompareTag()overtag ==to avoid GC alloc - ▸LayerMask is a bitmask — use
GetMask()instead of magic numbers - ▸Max 32 layers; uncheck Collision Matrix pairs you do not need
⚠️ Common mistakes
❌ Using gameObject.tag == "Player"
String allocation every call → GC pressure
✅ gameObject.CompareTag("Player")
❌ Hardcoded layer bits: layerMask = 8
Breaks when layer order changes
✅ LayerMask.GetMask("Ground")