Bitmask Tutorial

A short tutorial on bitmasks.

There are several bitmasks used in various places in the package. These may not be familiar to all users, so in this tutorial I will briefly explain how they are used.

What is a bitmask?

A bitmask is a very efficient way to represent a set of options that can be enabled or disabled. A common example that is used both in Unity and in this package is layer masks. Layer masks represent a set of layers. For example, if you have a light, you could set a layer mask to determine which layers it should cast light on. In this package, layer masks are used for: selecting sets of layers to use, sets of graphs, sets of tags and sets of RVO layers.

A bitmask is represented in a single number, usually a 32-bit integer. Since we have 32 bits in that number, this means that we have 32 options that we can turn on and off.

For simplicity, let's say we have a 3-bit number and 3 options: "A", "B" and "C". In this 3-bit number, we can use the first bit to determine if option "A" is enabled, the second bit to determine if "B" is enabled, and the last bit for "C". For example, the number 6, which is 110 in binary, means that "B" and "C" are enabled, but "A" is disabled. 2 or 010 in binary would mean that only option "B" is enabled. In the same way, we can use this for 32-bit numbers.

Creating bitmasks

In code, you can easily create bitmasks using bitshifts and bitwise-or.

A bitshift essentially just moves some bits in a direction. 1 = 1 (in binary)
1 << 0 = 1 (in binary)
1 << 1 = 10 (in binary)
1 << 2 = 100 (in binary)
// etc.
57 = 111001 (in binary)
57 << 2 = 11100100 (in binary)

A bitwise-or will set a bit to 1 if the bit was 1 in either of the two numbers.

If we want to enable options 0, 3 and 4, we can construct individual bitmasks for enabling the options separately and then OR the bitmasks together. var mask0 = 1 << 0; // in binary: 00001
var mask3 = 1 << 3; // in binary: 01000
var mask4 = 1 << 4; // in binary: 10000
// Use a bitwise-or to create the mask
var fullMask = mask0 | mask3 | mask4; // in binary: 11001

// Or combined
var fullMask = (1 << 4) | (1 << 3) | (1 << 0); // in binary: 11001
The value -1 is represented in binary as all 1s. So -1 means that all options are enabled. Similarly, the value 0 means no options are enabled.

For more information, check out the Wikipedia article on the subject.

Uses in the package

The most common use of bitmasks in the package is for selecting which graphs are going to be searched when querying for the closest node to a point. The NNConstraint class has a field called 'graphMask' which determines which graphs are going to be searched. // Create a constraint that will search only the graphs with index 0 and 3
NNConstraint nn = NNConstraint.Walkable;

nn.graphMask = 1 << 0 | 1 << 3;

var info = AstarPath.active.GetNearest(somePoint, nn);
The Seeker.StartPath method also takes a parameter called 'graphMask' which is just forwarded to the Path.nnConstraint object. It can be used in the same way. // Schedule a path search that will only start searching the graphs with index 0 and 3
seeker.StartPath(startPoint, endPoint, null, 1 << 0 | 1 << 3);
There's also a built-in struct called GraphMask to help you build masks that represent different graphs:

GraphMask mask1 = GraphMask.FromGraphName("My Grid Graph");
GraphMask mask2 = GraphMask.FromGraphName("My Other Grid Graph");

NNConstraint nn = NNConstraint.Walkable;

nn.graphMask = mask1 | mask2;

// Find the node closest to somePoint which is either in 'My Grid Graph' OR in 'My Other Grid Graph'
var info = AstarPath.active.GetNearest(somePoint, nn);