How to work in bitwise?

kupo15

Member
I'm trying to revamp my replay code. Instead of being like:

left = t/f
right = t/f
down = t/f
etc...

It'll be much more effecient if I use one variable and assign as bit flags like

directional = 1101101;

but I'm not sure how to do this. How do I create these values and then read them?
 
H

Homunculus

Guest
If you set the bits manually, you are overcomplicating things, you don't really need to set the zeroes or the bit shifting. Assuming you saved your bits in a variable called flags , to get 1010 (starting from 0000) you can do this
Code:
flags = flags | 2; //0010
flags = flags | 8; //1000
You can also use an enum (or a macro) to label your flags and make it more readable:
Code:
enum DIR {
    left = 1,
    right = 2,
    up = 4,
    down = 8,
}
Then, to set for example the flags for up and left
Code:
flags = flags | DIR.left | DIR.up;
In order to read the value of a specific flag, you can use the above enum definition as well
Code:
var up = flags & DIR.up; //this will result in up = 4 if the bit is set, up = 0 if not set.
 

Conbeef

Member
I wrote something up really quick. It doesn't use binary, but strings instead. You can get exactly what you want from it this way if you wish.

////Create Event

actionStrList = "000000";
enum Dir{
left = 1,
right = 2,
up = 3,
down = 4,
attack1 = 5,
attack2 = 6
}

//////Script
///scr_actionList_set(index, value)
var _val = string(argument1);
var _Str = string_delete(actionStrList, argument0, 1);
actionStrList = string_insert(_val, _Str, argument0);


///////Script
///scr_actionList_get(index)
return string_char_at(actionStrList, argument0);


example use
scr_actionList_set(Dir.right, true);////or you can pass "1" straight in if you like


when you want to return the results us this
scr_actionList_get(Dir.right); this returns the string value at that position. simple use real() to make it a real number

real(scr_actionList_get(Dir.right))
 

TheouAegis

Member
Code:
enum DIR {
    RT = 1,
    UP = 2,
    LT = 4,
    DN = 8
}

input_previous = input;
input = ((keyboard_check(vk_down)<<1|keyboard_check(vk_left) )<<1|keyboard_check(vk_up) )<<1|keyboard_check(vk_right);
To see if a key (e.g., up) is held:
if input & DIR.UP

To see if a key is pressed:
if input | input_previous ^ input_previous & DIR.UP

To see if a key is released:
if input | input_previous ^ input & DIR.UP

Edit: Always poll inputs in Begin Step and only once per input.
 
Last edited:

kupo15

Member
If you set the bits manually, you are overcomplicating things, you don't really need to set the zeroes or the bit shifting. Assuming you saved your bits in a variable called flags , to get 1010 (starting from 0000) you can do this
Code:
flags = flags | 2; //0010
flags = flags | 8; //1000
You can also use an enum (or a macro) to label your flags and make it more readable:
Code:
enum DIR {
    left = 1,
    right = 2,
    up = 4,
    down = 8,
}
Then, to set for example the flags for up and left
Code:
flags = flags | DIR.left | DIR.up;
In order to read the value of a specific flag, you can use the above enum definition as well
Code:
var up = flags & DIR.up; //this will result in up = 4 if the bit is set, up = 0 if not set.
Thanks! Enums are an interesting idea, though at this point its no bother to hardcode the numbers since its an isolated script.

Yeah, I set the 0's because it was in a test project but in the game it'll actually be set because the code is referencing the state of the variables. It seems cleaner to bitshift for setting the flags. The first flag is the indicator if the input has changed and thus needs saving to the buffer, though I guess I could easily just check that the array index is not 0 instead of giving it its own flag. This is what I did for setting
upload_2019-8-24_22-2-3.png


Going with the reading, if I reverse it the numbers get quite ridiculous. Is this ok to do? I don't think there is a buffer type that's big enough to store that number, I would probably have to split it up
upload_2019-8-24_22-7-1.png

I realize I would have to add another condition that the bitwise result does not equal 0 so the value is a bool.

I wrote something up really quick. It doesn't use binary, but strings instead. You can get exactly what you want from it this way if you wish.
That seems really clever! Especially with all the big numbers I would be using. Will this be as small data saving wise as the bitwise number? I'm saving this variable to a buffer. A string with 32 characters seems like its more manageable and would work nicely, I would be using buffer_string?
Code:
enum DIR {
    RT = 1,
    UP = 2,
    LT = 4,
    DN = 8
}

input_previous = input;
input = ((keyboard_check(vk_down)<<1|keyboard_check(vk_left) )<<1|keyboard_check(vk_up) )<<1|keyboard_check(vk_right);
To see if a key (e.g., up) is held:
if input & DIR.UP

To see if a key is pressed:
if input | input_previous ^ input_previous & DIR.UP

To see if a key is released:
if input | input_previous ^ input & DIR.UP

Edit: Always poll inputs in Begin Step and only once per input.
Yep that is what I'm doing. I'm setting all these vars in the Begin step then saving their value to an array every step that an input is active, which I loop through and save to a buffer
 

TheouAegis

Member
You don't need to store the diagonal key presses as separate precious. That completely negates the point of using bitwise input handling. if the bit for rate is set in the bit for up a set, then actually the player is holding upright. If you were trying to incorporate 16 direction of movement, which would really only be logical with a joystick, then that would make more sense.

and as for whether or not you need to store whether a key is pressed or not, that depends on how often you are saving the inputs. But even if you were saving the inputs only every fourth step, I still think saving key presses might be redundant. and if you are recording the input every single step, then it for sure is redundant, because whatever the input was last step will tell you whether or not a key was pressed on the next step. That is why in my code I only record up held, down held, right held, and left held, because it doesn't matter if a button was pressed or not, all that matters is what button is currently down and what button was down last step.
 
H

Homunculus

Guest
You are using 32 bits, of course it’s going to fit in a buffer, it’s just 4 bytes. Using a string you will probably need at least 32 bytes. At that point you might as well use an array of booleans, I don’t get the point of using a string for this.

In this scenario you are right about but shifting, it’s more readable since you are not using names values for the flags.
 

kupo15

Member
You don't need to store the diagonal key presses as separate precious. That completely negates the point of using bitwise input handling. if the bit for rate is set in the bit for up a set, then actually the player is holding upright. If you were trying to incorporate 16 direction of movement, which would really only be logical with a joystick, then that would make more sense.

and as for whether or not you need to store whether a key is pressed or not, that depends on how often you are saving the inputs. But even if you were saving the inputs only every fourth step, I still think saving key presses might be redundant. and if you are recording the input every single step, then it for sure is redundant, because whatever the input was last step will tell you whether or not a key was pressed on the next step. That is why in my code I only record up held, down held, right held, and left held, because it doesn't matter if a button was pressed or not, all that matters is what button is currently down and what button was down last step.
Good points about the redundancies. I can definitely remove the diagonal helds. I definitely believe I need to save all the presses because this is for my fighting game and I handle each directional press as an attack input. But I guess its easy to use the u/l/r/d held inputs to determine if a key was pressed as you said by comparing it to the last frame. I could probably remove those as well

How can you get away with not saving the inputs every frame? If you do it every 4 but the player does a different input in between those 4 frames, how is the replay going to be accurate?

You are using 32 bits, of course it’s going to fit in a buffer, it’s just 4 bytes. Using a string you will probably need at least 32 bytes. At that point you might as well use an array of booleans, I don’t get the point of using a string for this.

In this scenario you are right about but shifting, it’s more readable since you are not using names values for the flags.
Cool, ok I'll stick with what I'm doing then! I just thought that & by a really large number was ridiculous and seemed wrong to do!
 
Last edited:
H

Homunculus

Guest
There’s a limit but it’s 64bits as far as i know, which is a really huge number
 

kupo15

Member
There’s a limit but it’s 64bits as far as i know, which is a really huge number
You wouldn't do every 4 frames for a fighter. Pokemon could get away with it though.
Great I got it working now, thanks! Last question, what is the best way to save this to the buffer size-wise? @GMWolf

Currently I store all these values as a grid[frame,input] and do a grid_write and save that string. The other way to do it would be to save each value of each frame directly to the buffer

upload_2019-8-25_16-26-26.png

I would be enqueueing this for each player every frame during recording and to save it to the buffer, I would dequeue this massive queue and save as the appropriate buffer type. The next step after this would be to create a way to only store data on a frame if its needed so I'm not wasting space on blank data
 
Last edited:

GMWolf

aka fel666
I would skip the queue entirely and write the data straight to a buffer, and deal only with buffers for replay data.
Mostly because you will use a lot, lot less data that way. (Replay data for an entire fighting game match can get quite big).

If all you input is binary and independent, I would just store it in whatever type has as many bits as you need, one bit per input.
If you are feeling especially adventurous, you could add your own wrapper around buffers to manage any number of bits.

If you input is not all binary, I would store a frame by first having a bitfield that represents which values changed, followed by just the values that changed.


If values don't change every frame erratically, I would also use run length encoding.

That is when you first have a value to represent how many unique/same values you have.
Usually 0 < N <128 means you have N different value to read. And 128<N < 255 means you have one value to read that applies to the next (N - 128) frames.
(Sorry, terrible explanation I hope it makes sense).

In either case you can just read the data as a stream. Read a frame of data, process it, read another frame, etc.

If all your frames are the same size then seeking through the data is simple enough.

If, however, you end up with different sized frames, I would store another buffer which acts as an index. You could store the offset of every 10 frames or so. Then when seeking, seek to the nearest lower 10th frame, then read forward to the point you want to read.

Of course if you are just reading frames one after the other in order you don't need that.

Hope this answers your questions.
Or were you looking for more low level how to get the values into the buffer?
 

kupo15

Member
I would skip the queue entirely and write the data straight to a buffer, and deal only with buffers for replay data.
Oh that makes sense, the data required to create and fill the queue will take up a lot of space compared to just writing to the buffer in real time. And I guess if I write directly to the buffer, then I don't really need to worry about running out of program space or capping a replay time because its being stored outside of the program, right? Nevermind, I forgot you create and fill the buffer as a variable like normal then there is a separate write externally to save it for later which will be done for the "save replay" It'll probably still be best practice to designate a replay time and use buffer fixed instead of using buffer grow forever

I did it this way so the player can choose after the fact to save the replay or not. But I could just record the replay always and if they don't chose the save replay option, it deletes the buffer when they quit out or restart the match.

If all you input is binary and independent, I would just store it in whatever type has as many bits as you need, one bit per input.
Almost all the the inputs are binary, but I converted them to a single bitwise value. Are you recommending going back and treat them all as bools instead? The input_v/h are either -1 0 or 1 but thinking about it, I can probably not include them and recreate those values with the binary inputs that are recorded

If you input is not all binary, I would store a frame by first having a bitfield that represents which values changed, followed by just the values that changed.
Everything in the last chunk is not binary. It basically saves every variable state in the player to allow me to ff and rewind playback. I feel like how I'm handling this part of the replay is very janky because if the inputs are not replicated, things like the hitboxes won't appear since they are tied to a timer from the inputs. At some point I'll have to address it but converting to a buffer is the first step.
If all your frames are the same size then seeking through the data is simple enough.
It might be easier to first do this method and not take into account not having to save non changing things. I'll be wasting space this method but it'll work as a first step
Or were you looking for more low level how to get the values into the buffer?
Nope, I know how to read and write to buffers thanks to your tuts! :D
 
Last edited:

TheouAegis

Member
The replay doesn't start at the beginning of the fight, right? You're doing something like a "last 5 seconds" replay? Because if you were going to record the entire match, you wouldn't even need to store 90% of that stuff, just which characters are fighting, which stage, and the button inputs. Even easier this way if you program the CPU to simulate key presses.
 

kupo15

Member
The replay doesn't start at the beginning of the fight, right? You're doing something like a "last 5 seconds" replay? Because if you were going to record the entire match, you wouldn't even need to store 90% of that stuff, just which characters are fighting, which stage, and the button inputs. Even easier this way if you program the CPU to simulate key presses.
It starts when you gain control of the character and for the entire match. Yes that is exactly what I'm doing, recording the inputs and letting the CPU run the inputs which works great for a straight forward playback. But if I want to be able to rewind the playback, how would I do that without recording status data like image_index, position, sprite etc and only using inputs? I don't think that's possible.
 

TheouAegis

Member
The same way you handle normal gameplay. If the player is in his idol Sprite on frame 0 and the replay buffer says the next value is RIGHT, then naturally the players going to have his xscale set to face right and likely also change to the moving Sprite. The replay isn't going to keep track of the state of everything, it's just going to keep track of what inputs were pressed / simulated. the rest of your game is what is actually handling all of that other data such as sprites and speeds.

And don't even be put off by idea that this would actually be slow, it's actually going to be even faster than your normal gameplay. The player is going to be handled at about the same speed, maybe a little slower since you're using a buffer, but is still essentially the same thing. The player provides an input, the game interprets that input. And the replay, the buffer provides the input, the game interprets the input. With the computer, it's actually going to be faster because you no longer have to go through the algorithms of deciding what the next move is going to be, you just read the input from the buffer and the game interprets that input for the computer.
 

GMWolf

aka fel666
The same way you handle normal gameplay. If the player is in his idol Sprite on frame 0 and the replay buffer says the next value is RIGHT, then naturally the players going to have his xscale set to face right and likely also change to the moving Sprite. The replay isn't going to keep track of the state of everything, it's just going to keep track of what inputs were pressed / simulated. the rest of your game is what is actually handling all of that other data such as sprites and speeds.

And don't even be put off by idea that this would actually be slow, it's actually going to be even faster than your normal gameplay. The player is going to be handled at about the same speed, maybe a little slower since you're using a buffer, but is still essentially the same thing. The player provides an input, the game interprets that input. And the replay, the buffer provides the input, the game interprets the input. With the computer, it's actually going to be faster because you no longer have to go through the algorithms of deciding what the next move is going to be, you just read the input from the buffer and the game interprets that input for the computer.
That doesn't always work.
Say the player is in the middle of the air.
Was he jumping or falling?
Is he moving upwards or downwards?

If you don't really need rewind, then I would avoid it and just store input info to do the playback.

If you really need playback ethats more than a couple seconds long what I would do is this:
1. store per frame input data.

2. store keyframes state. Perhaps every 10, 15, or even 30 frames, store the full state of the game (position, velocity, image index, whatever you need).

3. To get the state of any frame, first find the keyframe that came before, then simulate forward from there using input data.

4. To rewind, keep simulating that way, you *could* even cache that data, so if you are rewinding from frame 50, first calculate frames 40 to 49 in one block (by going forward from frame 40) and play through then, then frame 30-39, etc...
This should be fairly fast, and use very little memory.


[Edit]
Having a robust recording system that can replay a game backwards and forwards reliably can actually help in a lot of other systems, especially networked multiplayer (look at backwards reconciliation)
 
Last edited:

kupo15

Member
The same way you handle normal gameplay. If the player is in his idol Sprite on frame 0 and the replay buffer says the next value is RIGHT, then naturally the players going to have his xscale set to face right and likely also change to the moving Sprite. The replay isn't going to keep track of the state of everything, it's just going to keep track of what inputs were pressed / simulated. the rest of your game is what is actually handling all of that other data such as sprites and speeds.
Yep, that's how I currently am doing it. The replays already works moving forwards by simulating the player's recorded inputs as if they were happening live. I was saying without recording the full stats, there is no way to accurately rewind the replay to figure out what came before it. Inputs only will only work if the replay can only play forward, but not backward

That doesn't always work.
Say the player is in the middle of the air.
Was he jumping or falling?
Is he moving upwards or downwards?

If you don't really need rewind, then I would avoid it and just store input info to do the playback.

If you really need playback ethats more than a couple seconds long what I would do is this:
1. store per frame input data.

2. store keyframes state. Perhaps every 10, 15, or even 30 frames, store the full state of the game (position, velocity, image index, whatever you need).

3. To get the state of any frame, first find the keyframe that came before, then simulate forward from there using input data.

4. To rewind, keep simulating that way, you *could* even cache that data, so if you are rewinding from frame 50, first calculate frames 40 to 49 in one block (by going forward from frame 40) and play through then, then frame 30-39, etc...
This should be fairly fast, and use very little memory.


[Edit]
Having a robust recording system that can replay a game backwards and forwards reliably can actually help in a lot of other systems, especially networked multiplayer (look at backwards reconciliation)
Yep exactly right, full data is needed at some point. Another example being if I'm rewinding from an idle animation and it hits the start of it, what animation played before it? Can't know unless you record it. Your idea for storing full states every so often is a good one.

How would you store the inputs in the buffer, as a single bitwise value like I currently have or each as a bool?
 

TheouAegis

Member
Store as much data as you can in one byte. Which is 8 possible inputs. You can have more than eight buttons, but some of those buttons need to be duplicate pairs, such as having a and left both assigned to moving left.

And then for coordinates, you need to figure out how many bytes your room with will take up and how many bytes your players can traverse up and down. If your room is only 256 pixels wide, then you only need one byte for x. If it's 1000 pixels wide, you'll need two bytes. and what I meant for the vertical part is even if your room is more than 256 pixels high, it shouldn't matter if the player could only move 240 pixels above the ground. In other words, say the player could jump 150 pixels up and the opponent could then knock him up another 60 pixels higher. That's still less than one bite total distance, so you would only need one bite for the y-coordinate and then you would use the ground as point zero.
 

GMWolf

aka fel666
Store as much data as you can in one byte. Which is 8 possible inputs. You can have more than eight buttons, but some of those buttons need to be duplicate pairs, such as having a and left both assigned to moving left.

And then for coordinates, you need to figure out how many bytes your room with will take up and how many bytes your players can traverse up and down. If your room is only 256 pixels wide, then you only need one byte for x. If it's 1000 pixels wide, you'll need two bytes. and what I meant for the vertical part is even if your room is more than 256 pixels high, it shouldn't matter if the player could only move 240 pixels above the ground. In other words, say the player could jump 150 pixels up and the opponent could then knock him up another 60 pixels higher. That's still less than one bite total distance, so you would only need one bite for the y-coordinate and then you would use the ground as point zero.
Unless yoibhave subpixel movement.
Then you have to store the data in whatever precision you use for the game.

Quite hard to do with GM, so if I was you, and not using GM, I would have the game state be its own data thing, and have a function to get the next game state from that game state.
Then the function to go forward in the recording, or to simulate the world would be the same.
Works well for fighting games since your only have 2 entities to really keep track of.

With GM doing that, you kinda throw out a lot of what GM does for you, so probably not worth doing.
 

kupo15

Member
Store as much data as you can in one byte. Which is 8 possible inputs. You can have more than eight buttons, but some of those buttons need to be duplicate pairs, such as having a and left both assigned to moving left.
Ok, so if I have 32 inputs, instead of combining them all into one bitwise I should split them up into 4 buffer_u8 values?
And then for coordinates, you need to figure out how many bytes your room with will take up and how many bytes your players can traverse up and down. If your room is only 256 pixels wide, then you only need one byte for x. If it's 1000 pixels wide, you'll need two bytes. and what I meant for the vertical part is even if your room is more than 256 pixels high, it shouldn't matter if the player could only move 240 pixels above the ground. In other words, say the player could jump 150 pixels up and the opponent could then knock him up another 60 pixels higher. That's still less than one bite total distance, so you would only need one bite for the y-coordinate and then you would use the ground as point zero.
Clever to reduce the size. I thought about that for width but not for the potential vertical limit

Unless yoibhave subpixel movement.
Then you have to store the data in whatever precision you use for the game.

Quite hard to do with GM, so if I was you, and not using GM, I would have the game state be its own data thing, and have a function to get the next game state from that game state.
Then the function to go forward in the recording, or to simulate the world would be the same.
Works well for fighting games since your only have 2 entities to really keep track of.

With GM doing that, you kinda throw out a lot of what GM does for you, so probably not worth doing.
Yeah, having a separate buffer for the game state sounds like a good idea. I believe I don't work in subpixels...but I'm not sure.
 

TheouAegis

Member
Ok, so if I have 32 inputs,
What are all your inputs? That seems excessive... Remember, "input" does not mean key/button. So looking at, let's say a PlayStation controller, there are 16 buttons (and two analog sticks, but we will ignore those), so each controller's state is stored in 2 bytes. so as long as the player has access to two controllers, the player wouldn't theory have access to 32 buttons, or 4 bytes. simple enough. Let's say the player is playing a game which has only 10 inputs - shoot, attack, up, down, left, right, pause, menu select, look left, look right. It has 10 inputs, so you would think you would need to store 2 bytes of data, but you only need to store 1 byte of data, since four of those inputs have no bearing on a replay. So, if you have 32 input in your game, I wonder how many of those are being confused as buttons, and if there is no misunderstanding there, how many of those inputs are necessary to be saved for a replay.
 

kupo15

Member
What are all your inputs? That seems excessive... Remember, "input" does not mean key/button. So looking at, let's say a PlayStation controller, there are 16 buttons (and two analog sticks, but we will ignore those), so each controller's state is stored in 2 bytes. so as long as the player has access to two controllers, the player wouldn't theory have access to 32 buttons, or 4 bytes. simple enough. Let's say the player is playing a game which has only 10 inputs - shoot, attack, up, down, left, right, pause, menu select, look left, look right. It has 10 inputs, so you would think you would need to store 2 bytes of data, but you only need to store 1 byte of data, since four of those inputs have no bearing on a replay. So, if you have 32 input in your game, I wonder how many of those are being confused as buttons, and if there is no misunderstanding there, how many of those inputs are necessary to be saved for a replay.
Oh I see what you mean. I guess at the moment I'm not recording just the inputs from the controller and replaying those but rather recording the input variables created from it and overwriting those variables created by the input code. So instead I should be running the recorded inputs to generate the variables (example, kick pressed, kick held, kick released all use the same button, only needs to record one button and generate the 3 states from it)
 
Top