Monday, 9 July 2012

Bit Flags in XNA


OK, this might be a bit off the beat and track of my normal posts, but I ad forgotten all about these little fellows and remembered them while playing with some old Win32 API’s. So, what are Bit Flags, well for want of a better description, it’s a way of storing more than one value in a variable. Now you can’t just store any old values in them but we will come to that.

The last time I used these was a fair few years ago when I was helping a friend (Matt Judge) write a MUD on Linux in CI think it was called Axia, , I know, madness… was fun though. Would love to know if this is still going, if you are out there Matt and read this, let me know :). Anyway, if I recall correctly we used them to store things like the players state, is he/she standing, walking, running, swimming etc, also for room locations, does the room have a north wall, a ceiling and so on.

So how do we use them in C# and why is there a restriction on the values we can use…?

First of all you need to know about logical bitwise operators and how they work, we are going to use them to set and test bits in a variable, this should also help explain why we can only use certain values. So what do I mean when I say we are going to set and test bits in a variable, well lest take an integer value of 8, in the bowels of your computer this number is represented by a binary value, a set of ones (1) and zeroes (0), lets see what the numbers from 0 to 10 look like in binary:


Integer Value Binary Value
0 00000000
1 00000001
2 00000010
3 00000011
4 00000100
5 00000101
6 00000110
7 00000111
8 00001000
9 00001001
10
00001010
Here I am showing the binary numbers as 8bit numbers, that is, there are 8 bits that can be used to represent a value. As we can see the number 8 in binary is 00001000 so to represent the number 8 we set the 4th bit in an 8bit number to 1 and ALL the others are 0. You can find all the binary values for 8bit numbers here, 8 bit number limit us to a max value of 255. If we have an integer and test the 4th bit and find it is 1, we know that it is the value of 8 right? No, look at 9 and 10, they also have the 4th bit set to 1, and this is why we can only use certain values, and these values must be powers of 2 or the number 1. So if we set the 4th bit and the 3nd bit in our variable we are able to store, 2 and 4 at the same time as we now know only numbers that are powers of 2 are used we know there will be no bit cross over.

If you look at a table of integer and binary like above that are only powers of 2 you can see that there is never a cross bit representation like this:

Integer Value Binary Value
1 00000000 00000000 00000000 00000001
2 00000000 00000000 00000000 00000010
4 00000000 00000000 00000000 00000100
8 00000000 00000000 00000000 00001000
16 00000000 00000000 00000000 00010000
32 00000000 00000000 00000000 00100000
64 00000000 00000000 00000000 01000000
128 00000000 00000000 00000000 10000000
256 00000000 00000000 00000001 00000000
512 00000000 00000000 00000010 00000000
1024 00000000 00000000 00000100 00000000
2048 00000000 00000000 00001000 00000000
4096 00000000 00000000 00010000 00000000
8192 00000000 00000000 00100000 00000000
16384 00000000 00000000 01000000 00000000
32768 00000000 00000000 10000000 00000000
65536 00000000 00000001 00000000 00000000
131072 00000000 00000010 00000000 00000000
262144 00000000 00000100 00000000 00000000
524288 00000000 00001000 00000000 00000000
1048576 00000000 00010000 00000000 00000000
2097152 00000000 00100000 00000000 00000000
4194304 00000000 01000000 00000000 00000000
8388608 00000000 10000000 00000000 00000000
16777216 00000001 00000000 00000000 00000000
33554432 00000010 00000000 00000000 00000000
67108864 00000100 00000000 00000000 00000000
134217728 00001000 00000000 00000000 00000000
268435456 00010000 00000000 00000000 00000000
536870912 00100000 00000000 00000000 00000000
1073741824 01000000 00000000 00000000 00000000
2147483648 10000000 00000000 00000000 00000000
So now we have a list of 32bit binary values we can use as flags knowing that they will never cross bits. How do we set and test the bits? This is where our logical bitwise operators come in. So to set a bit in a variable we use the | (or) operator, this will set the variables bits to the value we want like this:

int value2 = 2;
int value4 = 4;
int value8 = 8;
int value = 0;
value = value2 | value8;

So the binary for value will look like this: 00001010 and will have the integer value of 10 (yes that’s how your computer does addition using binary!) This is what I love about bit flags, we have now got 2 values stored in one variable, value2 could represent if a weapon is equipped and value8 if it is loaded. If we call the | operator gain with the same values (value2 and value8), then there will be no change in value as the bits are already set.

But haw can we test if a value is set or not? This is done with the & (and) operator, this will test the variables bits like this:

int value2 = 2;
int value4 = 4;
int value8 = 8;
int value = 0;

value = value2 | value8;

int result = 0;

result = value & value2;
result = value & value4;

The first time we test if value2 is stored in value and it is so the result is populated with value2, the second time we test for value4 which is not in value so result is set to 0.

What if we want to just switch a bit on or off? For this we use the ^ (xor) operator, this will switch a bit that is set at 1 to 0 and one set at 0 to 1 effectively working like a light switch on the bit like this:

int value2 = 2;
int value4 = 4;
int value8 = 8;
int value = 0;

value ^= value2;
value ^= value2;

The first call sets value to hold value2, the second call removes value2 from value as it is already set.
In my days of working on Axia we used C macros to do the job but here, as C# does not support them (a good thing I think) I will use functions. I have created a simple XNA project that uses the above operators which you can download here.

In the project I use an enum to represent my bit flags like this:

public enum GunStates : int
{
Empty = 1,
Loading = 2,
Shooting = 4,
Equiped = 8,
Loaded = 16
}

Notice I have strong typed the enum as an int, you could use short, long, byte or what ever you need for the job you have in mind. The functions I use to set and check for states look like this:

public void SetGunState(GunStates stateSet)
{
state ^= stateSet;
}
public bool CheckGunState(GunStates stateChk)
{
return (state & stateChk) == stateChk;
}

You could also take a look at bitwise shift too (shift left << and shift right >>), these shift the bits of a variable in the given direction a number of bits, so value2 << 1 would shift all the bits in value2 to the left 1 and the resulting value stored in value2 would be 4, if you reset value2 to equal 2 and did value2 << 2 values2’s bits would be shifted to the left 2 bits to the left resulting in value2 having the value of 8, you could then set value2 back to 2 by doing value2 >> 2. So, a quick off the top of my head implementation of this would be for say a GSM manager where the states are hidden, showing, shown and hiding so by using bitwise shifts you can alter the state in a linear manner.

The Audio I used in this project I got from here, this is also credited in the source code.

As ever C&C are welcome.

No comments:

Post a Comment