Search Unity

Howto: if layermask contains layer?

Discussion in 'Scripting' started by half_voxel, Sep 11, 2009.

  1. half_voxel

    half_voxel

    Joined:
    Oct 20, 2007
    Posts:
    978
    Hi

    I have searched a bit on the forum for how to see if a layermasks layer is enabled, although I can only find how you create a layermask.
    The reason is that when building a custom inspector you can't create a LayerMask field, so I'm trying to create one myself.

    Is it something like
    Code (csharp):
    1. if (layermask == 1<<layer)
    ?
     
    Novack and AsierMR like this.
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    It's not quite as simple as that, unfortunately. The layer mask is an integer, and you need to test just a single bit. You need to do something like:-
    Code (csharp):
    1. if (((layermask >> layer)  1) == 1) {
    2.    ...
    3. }
    What this does is shift the bit that you want to test into the rightmost bit (ie, the digit that represents the value of 1). The bitwise-and operator then sets all bits except this one to zero. The value in the integer is then the value of the specific bit you want to test - it will be zero if false and one if true.
     
  3. half_voxel

    half_voxel

    Joined:
    Oct 20, 2007
    Posts:
    978
    Hi

    Thanks for the answer.
    Although, like 10 seconds before you answered I found another solution:
    Code (csharp):
    1. if (layermask == (layermask | (1 << layer))) {
    i.e if layermask equals layermask + my layer
    And now I got a full LayerMask field for custom inspectors :D

    Code (csharp):
    1. public static int LayerMaskField (LayerMask selected) {
    2.         ArrayList layers = new ArrayList ();
    3.         ArrayList layerNumbers = new ArrayList ();
    4.         string name = "";
    5.         for (int i=0;i<32;i++) {
    6.             string layerName = LayerMask.LayerToName (i);
    7.             if (layerName != "") {
    8.                 if (selected == (selected | (1 << i))) {
    9.                     layers.Add ("> "+layerName);
    10.                     name += layerName+", ";
    11.                 } else {
    12.                     layers.Add (layerName);
    13.                 }
    14.                 layerNumbers.Add (i);
    15.             }
    16.         }
    17.         bool preChange = GUI.changed;
    18.         GUI.changed = false;
    19.         int[] LayerNumbers = layerNumbers.ToArray (typeof(int)) as int[];
    20.         int newSelected = EditorGUILayout.Popup ("Mask",-1,layers.ToArray(typeof(string)) as string[],EditorStyles.layerMaskField);
    21.         if (GUI.changed) {
    22.             if (selected == (selected | (1 << LayerNumbers[newSelected]))) {
    23.                 selected = ~(1 << LayerNumbers[newSelected]);
    24.                 Debug.Log ("Set Layer "+LayerMask.LayerToName (LayerNumbers[newSelected]) + " To False "+selected.value);
    25.             } else {
    26.                 Debug.Log ("Set Layer "+LayerMask.LayerToName (LayerNumbers[newSelected]) + " To True "+selected.value);
    27.                 selected = selected | (1 << LayerNumbers[newSelected]);
    28.             }
    29.         } else {
    30.             GUI.changed = preChange;
    31.         }
    32.         return selected;
    33.     }
     
    AsierMR, Omnikar and hersheys72 like this.
  4. davididev2

    davididev2

    Joined:
    Jan 25, 2016
    Posts:
    2
    By the way, custom editor scripts CAN use the default inspector:
    public override void OnInspectorGUI ()
    {
    base.OnInspectorGUI();
    // ...More code here
    }

    And for any custom fields, use [HideInInspector] right next to the decleration. :)
     
  5. demonpants

    demonpants

    Joined:
    Oct 3, 2008
    Posts:
    82
    Those are both "harder" than this more common method (and IMO also less intuitive):

    Code (CSharp):
    1. if (layerMask & (1 << layer) != 0)
    2. {
    3.     Debug.Log("I belong in this mask.");
    4. }
    It works because the 1 << layer creates an int with a single bit shifted over layer number times (layer 1 gives you 0001, layer 2 gives you 0010, layer 3 gives you 0100, etc). Then by using the bitwise and operator (&) it will return any bits that exist in both integers. So, it gives you a 0 if no bits match.
     
    eurobax, WayneJP and Devastadus like this.
  6. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    at least in Unity 2020, this throws an error: error CS0019: Operator '&' cannot be applied to operands of type 'LayerMask' and 'bool'
     
    Bunny83 likes this.
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,990
    Not just in Unity 2020 ^^. Have a look at the Operators Precedence in C#. So the shift operator has the highest priority of the 3 operators we used. Therefore the brackets he used are pointless since the shift is done first anyways. However the issue is that the comparison operator
    !=
    has a higher priority than the bitwise AND operator
    &
    . So when we break down his code it actually tries to do this

    Code (CSharp):
    1. int mask = 1 << layer;
    2. bool tmp = mask != 0;
    3. bool result = layerMask & tmp;
    4. if(result)
    5.  
    hopefully you see the result line makes no sense since we try to use the bitwise AND between a layermask and a boolean value. What you have to do is using brackets like this

    if ((layerMask & 1 << layer) != 0)


    This will result in this code

    Code (CSharp):
    1. int mask = 1 << layer;
    2. int tmp = layermask & mask ;
    3. bool result = tmp != 0;
    4. if(result)
    5.  
     
    eurobax likes this.