- Home /
Type for layer selection
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.
Answer by Kyle_WG · Oct 29, 2014 at 03:19 PM
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.
It 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, $$anonymous$$yle_WG!
xkcd feelings, 2 years later. Thanks man, wherever/whenever you are.
Answer by MoruganKodi · Jun 28, 2017 at 06:22 AM
There 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:
@$$anonymous$$orugan$$anonymous$$odi .. 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.
Just so you know, your snippet here was directly used in the Oculus SD$$anonymous$$ 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.
One small thing to add: The code posted here works fine for displaying the Layer dropdown. However, it has one defect in modern versions of Unity: It doesn't cause fields on Prefabs to be marked as dirty under the new prefab workflow. With the code as-is, changing the layer on a prefab instance doesn't flag that field as having any changes.
"Fixing" that behavior simply requires wrapping the property.intValue setting in Begin/EndProperty, like this:
[CustomPropertyDrawer(typeof(LayerAttribute))]
public class LayerAttributeEditor : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
property.intValue = EditorGUI.LayerField(position, label, property.intValue);
EditorGUI.EndProperty();
}
}
"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);
Answer by mkgame · Nov 30, 2018 at 11:59 AM
Just 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 {
}
Your answer
Follow this Question
Related Questions
Making enum visible in the Inspector via a drop down list 2 Answers
A node in a childnode? 1 Answer
layer = layerMask (which is set in Inspector) 6 Answers
List to dropdown 0 Answers
How can I have a raycast ignore a layer completely? 2 Answers