P
Paolo Mazzon
Guest
GM Version: Studio and up
Target Platform: All
Download: N/A
Links: The documentation on bitwise operations
Summary:
An in depth tutorial to teach you how to use binary operators to your benefit for beginners.
Tutorial:
First of all, I created a tool to let you easily test bitwise operations. You can download it here (Single runtime executable -- not installer). If you are new bitshifting, I recommend you download it to make visualizing and testing a tad easier.
If you don't want to use my program, the windows 10 calculator has a nifty little screen that allows you to play with the binary in programmer mode.
Anyway, onto the tutorial. I believe one of the least known topics to beginners is bitwise operations and their uses. I don't think I've ever seen a tutorial on such a thing, so I aim to make one. Since most people find binary and bitwise operations confusing, I'll try and keep it as simple as possible.
Before we go into the operators themselves, a few notes
All bitwise operators work by changing the value of a variable at their binary level. In GM, there are 5 operators: and (&), or (|), xor (^), shift right (>>), and shift left (<<). We will be going over each separately.
AND (&) Operator
This operator works by comparing the bits of one number to another and AND comparing them. For the result bit to be true, the two input bits must also be true. This means that if you provide the two inputs
0 0 0 1 0 1 1 0 (22)
1 0 0 1 0 0 1 0 (146)
The result would be
0 0 0 1 0 0 1 0 (18)
This is because only at position 1 and 4 are both of the two input bits equal to 1.
OR (|) Operator
OR is the same as AND, except only one of the two input bits need to be 1 for the output bit to be 1. Given the same two bytes, but with an OR instead of AND,
0 0 0 1 0 1 1 0 (22)
1 0 0 1 0 0 1 0 (146)
The result would then be
1 0 0 1 0 1 1 0 (150)
XOR (^) Operator
This one is a little bit more complicated to understand, but is much the same as the others. With this operator, one of the two input bits must be 1 for the output to be 1, but if both of the input bits are 1 then the output is false. Going off the same example
0 0 0 1 0 1 1 0 (22)
1 0 0 1 0 0 1 0 (146)
Would produce
1 0 0 0 0 1 0 0 (132)
The bits at position 1 and 4 are both true and because of that they output a 0.
Bitshift left (<<) Operator
This one as well as bitshift right are much easier to comprehend than the others; fret not. This one does what it sounds like, moves all the bits left by a certain amount. This is very easily displayed
0 0 0 1 0 1 1 0 (22)
becomes this when left shifted by 2
0 1 0 1 1 0 0 0 (88)
As you can clearly see, the ones were just shifted over 2 places. One thing to note, however, is that bits do not "wrap," so if you bitshift left by one and there is a bit at the very end, it will not loop back to the start, it will be gone.
Bitshift right (>>) Operator
Much like bitshift left, this one just shifts the bits, but to the right. The same example but to the right should suffice for this portion
0 0 0 1 0 1 1 0 (22)
becomes this when right shifted by 2
0 0 0 0 0 1 0 1 (5)
Uses of bitwise operators
In modern games, especially 2D, there are not too many purposes for this. That said, there are purposes.
One of the most common purposes is to use it for flags or options. SDL frequently uses them. How it works is quite simple -- you OR together several options into a single variable that you can then use AND to determine the options. In code, it looks something like this
This is quite simple to set up, you just need to make sure all the options equal n ^ 2. This might look like
When you OR together tall and orc, you get
0 0 0 0 0 1 0 1 (5)
Which later you can use to test the options. To see if the option PLAYER_ORC was chosen, all you need to do is
This is very useful if there are several options to choose from that would mean you would need many arguments; you can turn several arguments into one using flags.
Another use commonly used in the early game programming days was bitshift left and right by 1, since bit shifting left by 1 is the same as multiplying by 2, and bit shifting right by one is the same as dividing by 2; also without risking dividing by 0 problems. This was only really used, however, because the hardware back then was very weak and bitshifting is faster than multiplication and division. At this same time, storing several bool values is one byte was commonly used since ram was so scarce and a boolean value only requires one bit yet uses 8. If you had 80 bytes worth of boolean variables, you could turn that into 10 bytes with some bitwise operations.
The example mentioned by Nocturne is very practical in many games. In the case that you have a grid that is power of 2 in size, instead of dividing then flooring x/y coordinates, you can simply right bit shift.
This is also a very flexible solution. If you had a 16 * 16 grid, you could bitshift right by 4.
There are other uses such as string encoding, but that would require a fair bit of code to display and are easily found via a Google search. Anyway, I hope this was of some help to you and may possibly help you in the future.
Target Platform: All
Download: N/A
Links: The documentation on bitwise operations
Summary:
An in depth tutorial to teach you how to use binary operators to your benefit for beginners.
Tutorial:
First of all, I created a tool to let you easily test bitwise operations. You can download it here (Single runtime executable -- not installer). If you are new bitshifting, I recommend you download it to make visualizing and testing a tad easier.
Before we go into the operators themselves, a few notes
- You need to know how binary works before going over this tutorial
- It would be very helpful if you knew all the major logic gates
- All numbers in GML are equivalent to the C double; thus they are 64 bytes
- Gamemaker numbers are floats, so they behave quite strange when decimals are pressent
All bitwise operators work by changing the value of a variable at their binary level. In GM, there are 5 operators: and (&), or (|), xor (^), shift right (>>), and shift left (<<). We will be going over each separately.
AND (&) Operator
This operator works by comparing the bits of one number to another and AND comparing them. For the result bit to be true, the two input bits must also be true. This means that if you provide the two inputs
0 0 0 1 0 1 1 0 (22)
1 0 0 1 0 0 1 0 (146)
The result would be
0 0 0 1 0 0 1 0 (18)
This is because only at position 1 and 4 are both of the two input bits equal to 1.
OR (|) Operator
OR is the same as AND, except only one of the two input bits need to be 1 for the output bit to be 1. Given the same two bytes, but with an OR instead of AND,
0 0 0 1 0 1 1 0 (22)
1 0 0 1 0 0 1 0 (146)
The result would then be
1 0 0 1 0 1 1 0 (150)
XOR (^) Operator
This one is a little bit more complicated to understand, but is much the same as the others. With this operator, one of the two input bits must be 1 for the output to be 1, but if both of the input bits are 1 then the output is false. Going off the same example
0 0 0 1 0 1 1 0 (22)
1 0 0 1 0 0 1 0 (146)
Would produce
1 0 0 0 0 1 0 0 (132)
The bits at position 1 and 4 are both true and because of that they output a 0.
Bitshift left (<<) Operator
This one as well as bitshift right are much easier to comprehend than the others; fret not. This one does what it sounds like, moves all the bits left by a certain amount. This is very easily displayed
0 0 0 1 0 1 1 0 (22)
becomes this when left shifted by 2
0 1 0 1 1 0 0 0 (88)
As you can clearly see, the ones were just shifted over 2 places. One thing to note, however, is that bits do not "wrap," so if you bitshift left by one and there is a bit at the very end, it will not loop back to the start, it will be gone.
Bitshift right (>>) Operator
Much like bitshift left, this one just shifts the bits, but to the right. The same example but to the right should suffice for this portion
0 0 0 1 0 1 1 0 (22)
becomes this when right shifted by 2
0 0 0 0 0 1 0 1 (5)
Uses of bitwise operators
In modern games, especially 2D, there are not too many purposes for this. That said, there are purposes.
One of the most common purposes is to use it for flags or options. SDL frequently uses them. How it works is quite simple -- you OR together several options into a single variable that you can then use AND to determine the options. In code, it looks something like this
Code:
PlayerCreate(x, y, PLAYER_TALL | PLAYER_ORC);
Code:
PLAYER_TALL = 1;
PLAYER_BLACKSMITH = 2;
PLAYER_ORC = 4;
PLAYER_MAGE = 8;
0 0 0 0 0 1 0 1 (5)
Which later you can use to test the options. To see if the option PLAYER_ORC was chosen, all you need to do is
Code:
if (playerFlags & PLAYER_ORC > 0) {
// They flagged orc
}
Another use commonly used in the early game programming days was bitshift left and right by 1, since bit shifting left by 1 is the same as multiplying by 2, and bit shifting right by one is the same as dividing by 2; also without risking dividing by 0 problems. This was only really used, however, because the hardware back then was very weak and bitshifting is faster than multiplication and division. At this same time, storing several bool values is one byte was commonly used since ram was so scarce and a boolean value only requires one bit yet uses 8. If you had 80 bytes worth of boolean variables, you could turn that into 10 bytes with some bitwise operations.
The example mentioned by Nocturne is very practical in many games. In the case that you have a grid that is power of 2 in size, instead of dividing then flooring x/y coordinates, you can simply right bit shift.
Code:
// For this example, an 8 * 8 grid -- which means we can use >> 3 to divide by 8 and automatically floor
if (myGrid[# player.y >> 3, player.y >> 3] == 5) {
// stuff here
}
There are other uses such as string encoding, but that would require a fair bit of code to display and are easily found via a Google search. Anyway, I hope this was of some help to you and may possibly help you in the future.
Last edited by a moderator: