Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

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:
    977
    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)
    ?
     
  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.
     
    ludum_mubul and Omnikar like this.
  3. half_voxel

    half_voxel

    Joined:
    Oct 20, 2007
    Posts:
    977
    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.     }
     
    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,273
    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,543
    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.