Generates types for Tags and Layers in Unity projects - automatically, with no manual button pushes required. Simply set and forget!
The Tag / Layer Type Generator automatically generates types for the Tags and Layers defined in your Unity project. A developer can then use these types to ensure that at compile-time, any tags or layers used during runtime will be correct. Using tags and layers in this way ensures that should a tag or layer change, the .NET compiler will flag this as a compilation error long before bugs appear at runtime, which is often a symptom of using so-called 'magic strings'.
Using typed tags and layers in your project's code provides compile-time checking of the tag and layer values. Using the included Tag or Layer attributes on a string or int property respectively also allows you to adjust these values in the inspector. See examples below.
Whats wrong with UnityEngine.LayerMask?
Nothing! The generated types are designed to augment the usage of Unity's LayerMask struct. The LayerMask struct provides methods for converting a layer from a string into its corresponding ID (int) and vice versa. However, both approaches require you to use 'magic strings' in your code. Using typed values for both the layer id and the mask allows you to catch errors at compile time. The layer type also contains pre-computer masks for each layer, making it simple to create layer masks from the types.
The Tag / Layer Type Generator works out of the box, automatically and in the background with no dependencies other than Unity itself. It's pure CSharp and the public API has complete XML documentation including the generated CSharp types!
The Tag / Layer Type Generator subscribes to the Unity Editor's ProjectChanged event. When this event is raised, the generators check to see if any new tags or layers have been added or previous tags or layers have been updated. A new CSharp file is generated in either case. It's also possible to manually generate the files either via a button in the Project Settings windows or inspecting the TypeGeneratorSttings asset.
public sealed class Bullet : MonoBehaviour
{
private void OnCollisionEnter([Collision other)
{
// Used in CampareTag.
if (other.gameObject.CompareTag(Tag.Player)) {
Destroy(other.gameObject);
}
}
}
public sealed class TransparentFX : MonoBehaviour
{
private void Awake()
{
// Use the Layer ID for TransparentFX.
gameObject.layer = Layer.TransparentFX;
}
}
public class ExampleClass : MonoBehaviour
{
[SerializedField] private Camera _mainCamera;
void Start()
{
// Only render objects on the default layer.
_mainCamera.cullingMask = Layer.Mask.Default;
}
private void FixedUpdate()
{
// Collide against Water and Walls using their masks.
if (Physics.Raycast(transform.position, transform.forward, 20.0f, Layer.Mask.Water | Layer.Mask.Walls))
{
OnCollision();
}
}
}
If you want to use Tags or Layers as properties in a MonoBehaviour or ScriptableObject you can use the attributes provided. This will display a Tag or Layer field in the inspector.
public class ExampleClass : MonoBehaviour
{
[Tag] public string tag;
[Layer] public int layer;
// Unity already provides an inspecor for the UnityEngine.LayerMask struct.
public LayerMask layerMask;
private void OnCollisionEnter([Collision other)
{
// You can safely use the tag in CampareTag checks.
if (other.gameObject.CompareTag(tag)) {
Destroy(other.gameObject);
}
// ... or the layer ID
other.layer = layer;
}
}
A single configuration file is automatically created and placed into the Asset folder if one is not already available. This configuration file allows you to change the following parameters of both the Tag and Layer Types:
- Auto Generate (e.g.: Should the Tag or Layer file be automatically generated on changes to the project)
- Type Name (e.g.: Tag, Layer)
- File Path (e.g.: Scripts/Tag.cs, Scripts/Layer.cs)
- Optional: Namespace (e.g.: MyCustomNamespace)
- Optional: AssemblyDefinition (e.g.: MyCustomNamespace.MyCustomAssembly)
Note: If Assembly Definitions are used in your project, it's important to ensure that the File Path and AssemblyDefinition settings are set correctly, as the Generators use reflection against generated types to determine if new Tags or Layers have been added. It can only perform this reflection if it knows which Assembly Definition the generated types are compiled in. You can leave this set to none if Assembly Definitions aren't in use in the project.
Please see the API and Extensibility documentation.
This package can be added to your project via the Unity Asset Store.
This package is available on the openupm registry. It's recommended to install it via openupm-cli.
openupm add com.alkimeegames.taglayertypegenerator
Via the Package Manager, you can add the package as a Git dependency. Follow the instructions for Installing froma Git URL and further information around Git dependencies in Unity. We advise specifically locking to the main branch.
Open Packages/manifest.json with your favorite text editor. Add the following line to the dependencies block.
{
"dependencies": {
"com.alkimeegames.taglayertypegenerator": "https://github.com/AlkimeeGames/TagLayerTypeGenerator.git#main"
}
}
The Unity Package Manager records the current commit to a lock entry of the manifest.json. To update to the latest version, change the hash value manually or remove the lock entry to re-resolve the package.
"lock": {
"com.alkimeegames.taglayertypegenerator": {
"revision": "main",
"hash": "..."
}
}
namespace AlkimeeGames.Alkimee
{
/// <summary>
/// Use these string constants when comparing tags in code / scripts.
/// </summary>
/// <example>
/// <code>
/// if (other.gameObject.CompareTag(Tag.Player)) {
/// Destroy(other.gameObject);
/// }
/// </code>
/// </example>
public sealed class Tag
{
public const string Untagged = "Untagged";
public const string Respawn = "Respawn";
public const string Finish = "Finish";
public const string EditorOnly = "EditorOnly";
public const string MainCamera = "MainCamera";
public const string Player = "Player";
public const string GameController = "GameController";
public const string Collectable = "Collectable";
public const string Projectile = "Projectile";
}
}
namespace AlkimeeGames.Alkimee
{
/// <summary>
/// Use this type in place of layer names in code / scripts.
/// </summary>
/// <example>
/// <code>
/// if (other.gameObject.layer == Layer.Collectable) {
/// Destroy(other.gameObject);
/// }
/// </code>
/// </example>
public sealed class Layer
{
public const int Default = 0;
public const int TransparentFX = 1;
public const int IgnoreRaycast = 2;
public const int Water = 4;
public const int UI = 5;
public const int Collectable = 6;
public const int Layer30 = 30;
/// <summary>
/// Use this type in place of layer or layer mask values in code / scripts.
/// </summary>
/// <example>
/// <code>
/// if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out RaycastHit hit, Mathf.Infinity, Layer.Mask.Collectable | Layer.Mask.Water) {
/// Debug.Log("Did Hit");
/// }
/// </code>
/// </example>
public sealed class Mask
{
public const int Default = 1;
public const int TransparentFX = 2;
public const int IgnoreRaycast = 4;
public const int Water = 16;
public const int UI = 32;
public const int Collectable = 64;
public const int Layer30 = 1073741824;
}
}
}