How to get name or number of selected layer?

Hi. I’m new to Unity and C# so I’m about to learn the basics for both and I would like to ask for some help.

What I’m trying to do is a script that I can use to change the layer of an object to be something that I have selected from the inspector when the script is enabled.

I’m using C# and this is what I’m trying to do:

public LayerMask selectedLayer;

void onEnabled()
{
    gameObject.layer = selectedLayer;
}

But it doesn’t work because I get “layer is out of range (0…31)” error message.
I thought maybe it is because the layer class is requiering a number but the selectedLayer returns a string and I tried this instead:

gameObject.layer = LayerMask.NameToLayer(selectedLayer);

But it drop an error message saying a LayerMask can not be converted to a ‘string’.

Finally I was wondering what value is returned from the variable and I tried Debug.log(selectedLayer); to write the value in to the console and I get “UnityEngine.LayerMask”.
That’s it, no layer name or number returned from the variable and it makes me confused.

Anyone could explain please what am I doing wrong?

Thanks.
.

LayerMask is meant to be used for Raycasting and such, which means that it’s a layer mask. So if you select “Water” in the inspector, that’s the built in layer 4, and the integer value of the mask will be:

1 << 4 = 2 ^ 4 = 16

The idea of a layer mask is that it defines which of the 32 bits in the int which are set. So if your object is on layer 5, it matches a layer that has bit number 5 set to ‘1’, and does not match a layer with bit number 5 set to ‘0’.

There isn’t a class like LayerMask to make a layer dropdown. If you have a custom inspector, you can use EditorGUILayout.LayerField.

well that’s not going to work at all since the function unity hooks into is OnEnabled() not onEnabled()

Layer and LayerMask are different things, for different usages. They’re both numeric values though so c# with happily use them without throwing syntax errors, but they’re not interchangable.

Okay, I got soft, here’s how you get the dropdown. You need a property attribute:

using System;
using UnityEngine;

[AttributeUsage(AttributeTargets.Field)]
public class LayerAttribute : PropertyAttribute { }

You need a drawer:

//This goes in LayerAttributeDrawer.cs. This must be inside a folder named "Editor", otherwise your project won't compile for builds!
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof (LayerAttribute))]
public class LayerAttributeDrawer : PropertyDrawer {

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
        if (property.propertyType != SerializedPropertyType.Integer) {
            EditorGUI.LabelField(position, "The property has to be a layer for LayerAttribute to work!");
            return;
        }

        property.intValue = EditorGUI.LayerField(position, label, property.intValue);
    }
}

And you use it like this:

[Layer]
public int myLayer;

void OnEnable() {
    gameObject.layer = myLayer;
}

To explain, a class that inherits from Attribute can be put above a field (or a method or a class) in brackets. You can also drop the “Attribute” part from the name. So just having the class LayerAttribute : PropertyAttribute allows you to do [Layer] over a field. The [AttributeUsage(AttributeTargets.Field)] makes the code not compile if you put it over something else.

The PropertyDrawer class is a Unity-thing. It allows you to define how a field with a certain PropertyAttribute is drawn. So whenever Unity finds a field with [Layer] above it, it’ll look for a PropertyDrawer tagged as the [CustomAttributeDrawer] for Layer, and use that drawer’s OnGUI to draw the property instead of the default drawer for ints.

9 Likes

Thanks a lot for the explanations.

@Baste
I’m affraid at the moment to create an attribute is beyond my skills, I want to go slowly with this otherwise I miss the point and start asking silly questions. But when I get there, your example going to be definately helpful.

Thanks again.

I mean, you just have to copy-paste my code. That shouldn’t be too hard!

Of course it is not too hard but what I meant was, I don’t understand how the actual code works.
Even if it works I’d like to understand every single line and class used in the code not only copy-pase it but it feels too early to get in to that.
I’m only getting started with Unity and C# so I really need to get the basics out of the way first but I’m appreciat your help :slight_smile:

3 Likes