Bitfields for multiple flags in Unity

Demand

Supposed we’re going to develop a shooting game. Characters in our game have several flags such as IsMoving, IsShooting, IsLoading, IsHiding… All these behaviors might happen simultaneously (or, of course, individually), say, the character can shoot while moving, can load his gun while hiding. How are we going to set these flags?

The simplest way might be allocating bools for them respectively. However, bools in C# are stored as ints and the compiler might not be able to combines/consolidates them. So if there’re 16 bools, that’s an allocation of 16 ints – wasteful. In addition, if one of those combinations (eg. IsMoving + IsShooting) are frequently used, the codes might be burden.

Following are some tips for such situation.

Using Bitfields

A bitfield (or Flags in .NET-speak) is a way of specifying an enumeration such that a single field can have multiple enumeration values. In Unity, we can write:

/// <summary>
/// StatFlags enumeration
/// </summary>
[System.Flags]
public enum StatFlags
{
     IsIdle = 0,
     IsMoving = 1,
     IsShooting = 2,
     IsHiding = 4,
     IsLoading = 8,
     All = 15
}

public static class CharacterFlags
{
    public const int IsIdle = (int)StatFlags.IsIdle; // 0
    public const int IsMoving = (int)StatFlags.IsMoving; // 1
    public const int IsShooting = (int)StatFlags.IsShooting; // 2
    public const int IsHiding = (int)StatFlags.IsHiding; // 4
    public const int IsLoading = (int)StatFlags.IsLoading; // 8
    public const int All = (int)StatFlags.All; // 15
}

Bitwise operators can be applied to them:

// Initialize
int flags = CharacterFlags.IsIdle;

//Change
flags |= CharacterFlags.IsMoving; // Equal to set true
flags &= ~CharacterFlags.IsMoving; // Equal to set false

// Judge
int value;
if (((CharacterFlags)value & CharacterFlags.Health) == CharacterFlags.Health) { /* do sth */ }
if ((value & (int)CharacterFlags.Health) == (int)CharacterFlags.Health) { /* do sth */ }
if (((CharacterFlags)value & CharacterFlags.Health) != CharacterFlags.None) { /* do sth */ }
if ((value & (int)CharacterFlags.Health) != 0) { /* do sth */ }

We can also expose it in Unity:

// Now define the actual field, and tag on the EnumFlagsFieldAttribute.
[SerializeField, EnumFlagsField] StatFlags     _fieldName;

Further Thoughts

Based on features of bitfield, we might be able to combine 2 flags as follow (haven’t verify it, though):

IsMoving = 1;
IsRunning = 3; // If is running, must be moving

There’s a BitArray class and BitVector32 struct as well:
BitArray: https://msdn.microsoft.com/en-us/library/system.collections.bitarray(v=vs.110).aspx
BitVector32: https://msdn.microsoft.com/en-us/library/system.collections.specialized.bitvector32(v=vs.110).aspx

Conclusion

Anywhere we use bools (actually ints), we could use bits instead, yes. Bits have the advantage of being packed together in an int so that we can pass 32 of them at a time as a mask. The BitArray and BitVector32 constructs simply hide all the masking syntax (bitwise operators) so that we can access the bits using simple Boolean syntax.

 

Reference:

Bitfields in Unity: http://www.codingjargames.com/blog/2014/11/10/bitfields-in-unity/

Leave a Reply