Personally, I mostly just use [System.Flags] now whenever I need a multi-selection field in the inspector instead of that attribute drawer. This post started in 2013 before Unity was able to display [System.Flags] natively! Back then people had to invent that custom property, but now that there is [System.Flags], people don’t need those custom attributes much anymore. At the time when I wrote my post, I didn’t know that was the current situation.
However, you need to be aware that [System.Flags] requires that the enum be a mask. There is a mistake in my code above - sorry about that. The furniture type needs to be declared as:
[System.Flags]
public enum FurnitureMaskType { None = 0, Sofa = 1, Curtains = 1 << 1, Table = 1 << 2, Chairs = 1 << 3 }
But really that is all you need - you don’t need that custom property stuff at all! That code above will show up in the inspector as a combo-box. However, you do need to understand bitmasks.
Here’s a utility class that I often use that simplifies using bitmasks (BitmaskUtils.cs):
// functions for working with bit masks
public static class BitmaskUtils
{
//--------------- ulong --------------------//
// returns the mask with the specified bit set to one.
public static ulong SetBit(ulong mask, byte index)
{
return (1u << index) | mask;
}
// returns the mask with the specified bit set to zero.
public static ulong UnsetBit(ulong mask, byte index)
{
return mask & ~(1u << index);
}
// returns the mask with the specified bit set to one or zero based on enable.
public static ulong ToggleBit(ulong mask, byte index, bool enable)
{
return enable ? SetBit(mask, index) : UnsetBit(mask, index);
}
// returns true if the specified bit in the given mask is one.
public static bool IsBitSet(ulong mask, byte index)
{
return (mask & (1UL << index)) != 0;
}
// returns a mask where all the bits are set that are in either mask1 or mask2.
public static ulong SetBits(ulong mask1, uint mask2)
{
return mask1 | mask2;
}
// returns mask1 where all the bits that are 1 in mask2 are set to 0.
public static ulong UnsetBits(ulong mask1, uint mask2)
{
return mask1 & ~mask2;
}
// sets or unsets bits based on enable.
public static ulong ToggleBits(ulong mask1, uint mask2, bool enable)
{
return enable ? SetBits(mask1, mask2) : UnsetBits(mask1, mask2);
}
//--------------------- uint --------------------//
// returns the mask with the specified bit set to one.
public static uint SetBit(uint mask, byte index)
{
return (1u << index) | mask;
}
// returns the mask with the specified bit set to zero.
public static uint UnsetBit(uint mask, byte index)
{
return mask & ~(1u << index);
}
// returns the mask with the specified bit set to one or zero based on enable.
public static uint ToggleBit(uint mask, byte index, bool enable)
{
return enable ? SetBit(mask, index) : UnsetBit(mask, index);
}
// returns true if the specified bit in the given mask is one.
public static bool IsBitSet(uint mask, byte index)
{
return (mask & (1 << index)) != 0;
}
// returns a mask where all the bits are set that are in either mask1 or mask2.
public static uint SetBits(uint mask1, uint mask2)
{
return mask1 | mask2;
}
// returns mask1 where all the bits that are 1 in mask2 are set to 0.
public static uint UnsetBits(uint mask1, uint mask2)
{
return mask1 & ~mask2;
}
// sets or unsets bits based on enable.
public static uint ToggleBits(uint mask1, uint mask2, bool enable)
{
return enable ? SetBits(mask1, mask2) : UnsetBits(mask1, mask2);
}
//--------------------- byte --------------------//
// returns the mask with the specified bit set to one.
public static byte SetBit(byte mask, byte index)
{
return (byte)((1u << index) | mask);
}
// returns the mask with the specified bit set to zero.
public static byte UnsetBit(byte mask, byte index)
{
return (byte)(mask & ~(1u << index));
}
// returns the mask with the specified bit set to one or zero based on enable.
public static byte ToggleBit(byte mask, byte index, bool enable)
{
return enable ? SetBit(mask, index) : UnsetBit(mask, index);
}
// returns true if the specified bit in the given mask is one.
public static bool IsBitSet(byte mask, byte index)
{
return (mask & ((byte)1 << index)) != 0;
}
// returns a mask where all the bits are set that are in either mask1 or mask2.
public static byte SetBits(byte mask1, byte mask2)
{
return (byte)(mask1 | mask2);
}
// returns a mask where all the bits that are one is mask2 become zero in mask1.
public static byte UnsetBits(byte mask1, byte mask2)
{
return (byte)(mask1 & ~mask2);
}
// sets or unsets bits based on enable.
public static byte ToggleBits(byte mask1, byte mask2, bool enable)
{
return enable ? SetBits(mask1, mask2) : UnsetBits(mask1, mask2);
}
}