Thank you for that.
OK why are tags strings?!
And layers are ints (or worse strings)!
Not sure why Unity did not have some type that could be auto Inspected for these, while being optimal to compare.
I have grabbed Single Layer Inspector code before, now I need single tag inspector code (when it should be provided!)
/rant
the Cinemachine solution still exists once I worked out what to extract (not using Cinemachine), so thanks!!
Tags are for new beginners, when you get more advanced you realize markup components and similar are better tools in the toolbox
I use both - tags are super simple for quick checks. But a component can indeed give a lot more info, though not without some added weight
Tags never make sense. They are magic strings. Never use magic strings
Isn’t that what they have done again with UI Toolkit?! Please stop it with the magic strings - Unity Engine - Unity Discussions
I mean there’s my post after OP which shows a work around. We have always been able to Q<T> for strongly typed visual elements.
This is also completely off topic to the thread.
Tags are an old feature of Unity. They are no longer needed and could honestly be removed without any loss.
Today I came across this same problem, while trying to make a beginner-friendly tool. My solution was this:
- Property:
public sealed class TagMaskFieldAttribute : PropertyAttribute { }
[CustomPropertyDrawer(typeof(TagMaskFieldAttribute))]
public class TagMaskFieldAttributeEditor : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
property.stringValue = EditorGUI.TagField(position, label, property.stringValue);
}
- Implementation:
public class ScriptExample : MonoBehaviour
{
[SerializeField, TagMaskField] private string _tag;
}
- Inspector Result:
This works like a charm.
Hi, everyone
I managed to get the list of tags in TagManager.asset file under ProjectSettings.
Here is the script MyScript as an example.
using UnityEngine;
public class MyScript : MonoBehaviour
{
[SerializeField]
private string m_Tag = "Untagged";
[SerializeField]
private int m_SelectedIndex = 0;
[SerializeField]
private int m_SelectedValue = 0;
[SerializeField]
private int m_BitMask = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
Now the editor script MyEditor showing how to get all tags and display them on Inspector.
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
/// <summary>
///
/// </summary>
[CustomEditor(typeof(MyScript))]
public class MyEditor : Editor
{
// Tag for TagField
private SerializedProperty m_TagProp;
// Selected index for Popup
private SerializedProperty m_SelectedIndexProp;
// Selected index for IntPopup
private SerializedProperty m_SelectedValueProp;
// BitMask for MaskField
// 0 = Nothing
// -1 = Eveything
private SerializedProperty m_BitMaskProp;
// Labels
private GUIContent m_TagLabel = EditorGUIUtility.TrTextContent("Tag:", "Tooltip for Tag.");
private GUIContent m_PopupLabel = EditorGUIUtility.TrTextContent("Popup Tags:", "Tooltip for Popup.");
private GUIContent m_IntPopupLabel = EditorGUIUtility.TrTextContent("IntPopup Tags:", "Tooltip for IntPopup.");
private GUIContent m_MaskFieldLabel = EditorGUIUtility.TrTextContent("MaskField Tags:", "Tooltip for MaskField.");
// Default Unity Tags from all versions of Unity
// See https://docs.unity3d.com/Manual/Tags.html
private List<string> m_Tags = new List<string>(new string[]
{
"Untagged",
"Respawn",
"Finish",
"EditorOnly",
"MainCamera",
"Player",
"GameController"
});
// Labels for Popup and IntPopup
private GUIContent[] m_TagsDisplayedOptions = null;
private int[] m_TagsOptionValues = null;
void OnEnable()
{
m_TagProp = serializedObject.FindProperty("m_Tag");
m_SelectedIndexProp = serializedObject.FindProperty("m_SelectedIndex");
m_SelectedValueProp = serializedObject.FindProperty("m_SelectedValue");
m_BitMaskProp = serializedObject.FindProperty("m_BitMask");
// Look for custom tags in TagManager.asset under ProjectSettings
SerializedObject serializedTagManagerAssetObject = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
// The serialized property containing only custom tags
SerializedProperty tagsProp = serializedTagManagerAssetObject.FindProperty("tags");
// Adding custom tags in tags list
for (int i = 0; i < tagsProp.arraySize; i++)
m_Tags.Add(tagsProp.GetArrayElementAtIndex(i).stringValue);
m_TagsDisplayedOptions = m_Tags.ConvertAll(tag => EditorGUIUtility.TrTextContent(tag)).ToArray();
m_TagsOptionValues = new int[m_TagsDisplayedOptions.Length];
for (int i = 0; i < m_TagsOptionValues.Length; i++)
{
m_TagsOptionValues[i] = i;
}
}
public override void OnInspectorGUI()
{
// Update the serializedObject - always do this in the beginning of OnInspectorGUI.
serializedObject.Update();
// You can use Tag field
EditorGUILayout.BeginHorizontal();
m_TagProp.stringValue = EditorGUILayout.TagField(m_TagLabel, m_TagProp.stringValue, GUILayout.ExpandWidth(true));
EditorGUILayout.EndHorizontal();
// You can use Popup field
EditorGUILayout.BeginHorizontal();
m_SelectedIndexProp.intValue = EditorGUILayout.Popup(m_PopupLabel, m_SelectedIndexProp.intValue, m_TagsDisplayedOptions, GUILayout.ExpandWidth(true));
EditorGUILayout.EndHorizontal();
// You can use IntPopup field
EditorGUILayout.BeginHorizontal();
EditorGUILayout.IntPopup(m_SelectedValueProp, m_TagsDisplayedOptions, m_TagsOptionValues, m_IntPopupLabel, GUILayout.ExpandWidth(true));
EditorGUILayout.EndHorizontal();
// You can use MaskField field
EditorGUILayout.BeginHorizontal();
m_BitMaskProp.intValue = EditorGUILayout.MaskField(m_MaskFieldLabel, m_BitMaskProp.intValue, m_Tags.ToArray(), GUILayout.ExpandWidth(true));
EditorGUILayout.EndHorizontal();
// Apply changes to the serializedObject - always do this in the end of OnInspectorGUI.
serializedObject.ApplyModifiedProperties();
}
}
On Inspector, it’ll look like this
Let me know what you guys think
Thanks
That looks… incredibly roundabout compared to just getting all tags via the undocumented API methods to do so: UnityCsReference/Editor/Mono/InternalEditorUtility.bindings.cs at master · Unity-Technologies/UnityCsReference · GitHub
Though the real advice for this thread would be to not use tags. There are substantially better ways to do things these days.
I am trying to enqueue a Scriptable Render Pass for the MainCamera and comparing tags like this: renderingData.cameraData.camera.CompareTag
How else can I uniquely identify a camera from renderingData?
@spiney199
Which header to copy for this function you’ve mentioned here? UnityCsReference/Editor/Mono/InternalEditorUtility.bindings.cs at master · Unity-Technologies/UnityCsReference · GitHub
The things you can attach any number of in any combination to game objects… aka, components.
Wouldn’t call that a better way than tags in this case.
It is, because you can define data however you want on a component. You could also put data that drives the scriptable render pass on said component. You can’t do that with a tag: it’s just a string. And strings are really only good for displaying text.

