If I want to have layer-mask as member on my class I can use LayerMask type. But if I want to get single layer I have to use int and in that case I do not get nice dropdown-list of layers. Is there an easy way to define a member which would be displayed as a layer dropdown-list? Writing a custom Inspector doesn’t count as easy way.
5 Answers
5There is a much simpler solution. Don’t create a custom class to store your value, but rather just create an attribute - then the entire process becomes WAY simpler than @Kyle_WG 's answer.
First: you need just an empty Attribute class.
/// <summary>
/// Attribute to select a single layer.
/// </summary>
public class LayerAttribute : PropertyAttribute
{
// NOTHING - just oxygen.
}
And the PropertyDrawer (which becomes an editor for the attribute, instead of some excessive class to store value that shouldn’t need one.
This should go into your “Editor” scripts folder - or if you write assemblies instead - into your Whatever.Editor.dll assembly.
[CustomPropertyDrawer(typeof(LayerAttribute))]
class LayerAttributeEditor : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// One line of oxygen free code.
property.intValue = EditorGUI.LayerField(position, label, property.intValue);
}
}
So all you need to do to use it is the following (See Layer Attribute):
[SerializeField, Layer] int m_EditorLayer = 31;
And voila, you have a layer selection without gnarly code: 
An answer to an old post but I created a wrapper in C# for this issue cause I was tired of not being able to have one simple layer select or just using an integer.
For anyone else who stumbles on the message and issue. (heh) Always reminds me of this xkcd comic link text
Here’s the wrapper class:
using UnityEngine;
[System.Serializable]
public class SingleUnityLayer
{
[SerializeField]
private int m_LayerIndex = 0;
public int LayerIndex
{
get { return m_LayerIndex; }
}
public void Set(int _layerIndex)
{
if (_layerIndex > 0 && _layerIndex < 32)
{
m_LayerIndex = _layerIndex;
}
}
public int Mask
{
get { return 1 << m_LayerIndex; }
}
}
And here’s the PropertyDrawer class. (Remember to throw it in a Editor folder in project.)
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(SingleUnityLayer))]
public class SingleUnityLayerPropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label)
{
EditorGUI.BeginProperty(_position, GUIContent.none, _property);
SerializedProperty layerIndex = _property.FindPropertyRelative("m_LayerIndex");
_position = EditorGUI.PrefixLabel(_position, GUIUtility.GetControlID(FocusType.Passive), _label);
if (layerIndex != null)
{
layerIndex.intValue = EditorGUI.LayerField(_position, layerIndex.intValue);
}
EditorGUI.EndProperty( );
}
}
I'll accept this as a suitable answer since it seems that there is no more simple solution.
– Paulius-LiekisIt may look gnarly, but this is the recommended way to extend editor functionality without writing custom inspectors for monobehaviours. This will give you the functionality you want, and all you have to do is drop these two classes in your project. Great work, Kyle_WG!
– AgamemjohnJust a bit more safer, because you can set the layer also in the source code:
using UnityEngine;
using System.Collections;
using System;
using UnityEditor;
[CustomPropertyDrawer(typeof(LayerAttribute))]
public class LayerAttributeEditor : PropertyDrawer {
public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label) {
EditorGUI.BeginProperty(pos, label, prop);
int index = prop.intValue;
if (index > 31) {
Debug.Log("CustomPropertyDrawer, layer index is to high '" + index + "', is set to 31.");
index = 31;
} else if (index < 0) {
Debug.Log("CustomPropertyDrawer, layer index is to low '" + index + "', is set to 0");
index = 0;
}
prop.intValue = EditorGUI.LayerField(pos, label, index);
EditorGUI.EndProperty();
}
}
public class LayerAttribute : PropertyAttribute {
}
I know I'm late but this brings problems because UnityEditor isn't included when building, unless you wrap the editor code in "#if UNITY_EDITOR" and #endif directives (excluding the custom property, obviously)
– MeatlyMind12 years later, but here we go lol:
[SerializeField] private LayerMask layer;
private void OnValidate()
{
int mask = layer.value;
if (mask != 0 && (mask & (mask - 1)) != 0)
{
// Keep only highest selected layer instead
int highest = 1 << (int)Mathf.Log(mask, 2);
layer = highest;
}
}
Hey, @Unity - isn’t it embarrassing that you still don’t have a single-layer selector for the editor? For at least twelve years (!!) people have posted workaround, custom property drawers and such. Do you have an office bet running or could you simply add that one day?
@MoruganKodi .. pretty swish avoiding the wrapper and directly using the property.intValue! I remember doing of object layer switching for camera effects so the ability to add functionality to the SingleLayer class won for me. Also the hard type helped in code design. Definitely prefer your way if you needn't extend like I did.
– Kyle_WGJust so you know, your snippet here was directly used in the Oculus SDK https://developer.oculus.com/downloads/package/oculus-utilities-for-unity-5/1.10.0/ : /OVR/Editor/OVRLayerAttributeEditor.cs "One line of oxygen free code." included haha.
– TribalInstincts"One line of oxygen free code." included here as well! Works well with prefabs and undo if you grab the serialized property like this in a CustomEditor OnInspectorGUI: var layerProperty = serializedObject.FindProperty(nameof(myCastedTarget.layerProperty)); layerProperty.intValue = EditorGUILayout.LayerField(new GUIContent("Label", "Tooltip text"), layerProperty.intValue);
– ToxicTree