# Get the Layernumber from a LayerMask

Discussion in 'Scripting' started by gamma.psh, Dec 6, 2011.

1. ### gamma.psh

Joined:
Jan 25, 2011
Posts:
44
I have a Problem with GameObject.layer which expects an int between 1-32 and LayerMask class

Lets say I have a Layer lets choose 20 and Call this layer "MyVeryImportantLayer"

Now there is a Class LayerMask and if this class is a public field then it shows up in my inspector, and I can say that it should represent "MyVeryImportantLayer".

Now my LayerMask.value is the same as 1 << 20 or also int 1048576 I could also write
Now why is there even a LayerMask.value, if LayerMask cast to int works the same, does this make any sense?

But how do i get this 20 out of a LayerMask value to set a GameObject to this Layer? something like

I more or less need the opposite function of 1 << 20 does someone know how this works?

2. ### ivkoni

Joined:
Jan 26, 2009
Posts:
978
Not exactly what you are asking for, but maybe you can use NameToLayer if you know the name.

3. ### Dreamora

Joined:
Apr 5, 2008
Posts:
26,598
it needs a dirty little trick. You have to 'reverse the bit shifting' of the layer value as it is a bit mask

layer.value = 1 << layerNumber (from editor) = 2^layerNumber

4. ### Dantus

Joined:
Oct 21, 2009
Posts:
5,668
You may check if aCertainLayerMask also contains layer number 20 as follows:

Code (csharp):
1. (aCertainLayerMask.value  (1 << 20)) != 0
.

If you want to check for more than just number 20, you need to check each of those numbers separately as far as I know.

Last edited: Dec 6, 2011
5. ### Ntero

Joined:
Apr 29, 2010
Posts:
1,436
You could do something like this:

Code (csharp):
1.
2. int layerNumber = 0;
3. int layer = myLayer.value;
4. while(layer > 0)
5. {
6.     layer = layer >> 1;
7.     layerNumber++;
8. }
9. return layerNumber;
10.
Essentially it just counts the number of bitshifts to get clear the flag. And unless you have multiple bit flags active it should return 20, to your 1 << 20.

6. ### gamma.psh

Joined:
Jan 25, 2011
Posts:
44
Ok thx, I just wanted to know if there is a easy way, but seems like i need to calculate it on my own.

like dreamora said the values of 1 << x are equal to 2^x.
Now whats special about these numbers is (2^0 + 2^1 + 2^2...2^n-1) < 2^n
This gives the possibility to calculate all the checked layers, and if Multiple layers are checked I throw a warning or do something other clever

I must even say that I feel a little bit stupid about my Question of course a LayerMask represents not strictly 1 Layer, so calculating the Layers from a Mask maybe gives me several results, what I didn't even think of -.-
But I think it was a good refresh about LayerMask's for me, thanks everyone

7. ### popeye1

Joined:
Dec 19, 2014
Posts:
28
Also believes its strange that given you have a Layermask you can't get the Layer name or the Layer number with any simple function. Ive found that you have to convert back your layer mask number to the layer number and then use LayerToName.

Last edited: Feb 25, 2015
8. ### kingandroid

Joined:
Nov 13, 2014
Posts:
9
Also in Unity 5 (as far as I know, havent checked the unity 4), the layer index start from 0, so you might wanna do
Code (csharp):
1. return layerNumber - 1;
to get correct result
or
Code (csharp):
1. while(layer > 1)

9. ### guneyozsan

Joined:
Feb 1, 2012
Posts:
47
Last edited: Apr 10, 2017
10. ### andrew-lukasik

Joined:
Jan 31, 2013
Posts:
101
@guneyozsan, Thank you for sharing this. I tested your method and, correct me if I'm wrong, it seem to not work for single case of 1<<31 (because it refers to -2147483648). Other are ok tho
1<<-1 returns -2147483648 expected fail
1<<0 returns 0 success
1<<1 returns 1 success
1<<17 returns 17 success
1<<30 returns 30 success
1<<31 returns -2147483648 fail
1<<32 returns 0 expected fail

Last edited: Apr 5, 2017
guneyozsan likes this.
11. ### andrew-lukasik

Joined:
Jan 31, 2013
Posts:
101
I find this to be best solution so far:
(based on @Ntero's post)
Code (CSharp):
1. /// <summary> Converts given bitmask to layer number </summary>
2. /// <returns> layer number </returns>
3. public static int ToLayer ( int bitmask ) {
4.     int result = bitmask>0 ? 0 : 31;
7.         result++;
8.     }
9.     return result;
10. }
1<<-1 returns 31 expected fail
1<<0 returns 0 success
1<<1 returns 1 success
1<<17 returns 17 success
1<<30 returns 30 success
1<<31 returns 31 success
1<<32 returns 0 expected fail

Post please if you have something more clever than this

Last edited: Apr 5, 2017
12. ### MitchStan

Joined:
Feb 26, 2007
Posts:
505
This. Screw all that bit shift crap. I have always used NameToLayer and LayerToName and never once used masks or bitshift.

You'll save yourself endless headaches if you just let the unity functions do the work for you.

13. ### andrew-lukasik

Joined:
Jan 31, 2013
Posts:
101
This well may be true @MitchStan
Or at least - matter of preference for string or integers. But since this topic seems dedicated to only one of them it makes sense to address it here and solve this volontary problem

Personally I just want to use nice, clear property names, like that:
Code (CSharp):
and (as of since now) that:
Code (CSharp):
1. if( otherGameObject.layer==Layer.Dynamic ) otherGameObject.layer = Layer.Static;
Code (CSharp):
1. public static class Layer {
2.
3.     public static class Mask {
4.
5.         public const int Static = 1<<12;
6.         public const int Dynamic = 1<<13;
7.         public const int Actors = 1<<9;
8.         public const int Bullets = 1<<10;
9.
10.         /// <summary> Converts given bitmask to layer number </summary>
11.         /// <returns> layer number </returns>
12.         public static int ToLayer ( int bitmask ) {
13.             int result = bitmask>0 ? 0 : 31;
16.                 result++;
17.             }
18.             return result;
19.         }
20.
21.     }
22.
23.     public static int Static { get { return Mask.ToLayer( Mask.Static ); } }
24.     public static int Dynamic { get { return Mask.ToLayer( Mask.Dynamic ); } }
25.     public static int Actors  { get { return Mask.ToLayer( Mask.Actors ); } }
26.     public static int Bullets  { get { return Mask.ToLayer( Mask.Bullets ); } }
27.
28. }
and I'm not totally sure yet which method would be better for this task. Seems like both can do the job just as well

Last edited: Apr 5, 2017
MitchStan likes this.
14. ### guneyozsan

Joined:
Feb 1, 2012
Posts:
47
@andrew-lukasik Wow, nice detail. Thanks for pointing out.

Joined:
Oct 21, 2016
Posts:
8
In case any one else needs to do something similar (useful for dynamic camera masks) and needs both the layer mask and the layer it may be helpful to make a stuct like so:

Code (CSharp):
1. using System;
2. using UnityEngine;
3.
4. [Serializable]
5. public struct Layer
6. {
7.     [SerializeField]
8.     int m_layer;
9.
10.     public int Index { get { return m_layer; } set { m_layer = value; } }
11.     public int Mask { get { return 1 << m_layer; } }
12.     public string Name
13.     {
14.         get { return LayerMask.LayerToName(m_layer); }
15.         set { m_layer = LayerMask.NameToLayer(value); }
16.     }
17.
18.     public static implicit operator int(Layer l)
19.     {
20.         return l.Index;
21.     }
22.
23.     public static implicit operator Layer(int i)
24.     {
25.         return new Layer() { Index = i };
26.     }
27.
28.     public Layer(int index)
29.     {
30.         m_layer = index;
31.     }
32.     public Layer(string name)
33.     {
35.     }
36. }
Can also be paired with a property drawer to make it display as a dropdown in the inspector:

Code (CSharp):
1. [CustomPropertyDrawer(typeof(Layer))]
2. public class LayerDrawer : PropertyDrawer
3. {
4.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
5.     {
6.         SerializedProperty layerProp = property.FindPropertyRelative("m_layer");
7.         layerProp.intValue = EditorGUI.LayerField(position, label, layerProp.intValue);
8.     }
9. }
Or just to fix the negative issue with @guneyozsan 's code produces, you can cast it to a uint in the interim (as well as a cast back to int as Mathf.Log only returns a float:
Code (CSharp):
1. layerNumber = (int)(Mathf.Log((uint)myLayer.value, 2))

guneyozsan and andrew-lukasik like this.
16. ### isbdnt

Joined:
May 16, 2017
Posts:
29
layerNumber = (int)(Mathf.Log((uint)myLayer.value, 2)) got large negative number with the default layer and below works well.
layerNumber = (int)(uint)Mathf.Log((uint)myLayer.value, 2)