When you’re working on a game, you might want to store whether in game events have occurred or not. For example; we may have a game where at some point a building is blown up. When we leave the room and come back, the building will reset to it’s un-blown up state unless we save variables.

I have, in the past, used an array to store different events. This always felt quite clunky to me and might require a lengthy array that’s difficult to keep track of. In this post I’ll explore how I use binary operators to allow me to store the status of many events by saving just one number.

A look at one of my poorly organised old projects shows how horrifying event management can end up

Update: this process is called bitmasking. When I came up with this and wrote this post, I had never actually heard of bitmasking.

If you’re not sure how binary operators work, the GameMaker Manual explains them really well. It’s where I learnt about them.

Specifically this method will use bitwise and (&), bitwise or (|) and bitwise not (~). Here’s a binary operator truth table for reference:

ABA&BA|BA&~B
00000
01010
10011
11110

Secondly, it really, really helps to use enums with this to make your events easy to keep track of. Again, you can learn about enums in the manual here.

So now I’ll provide an example. At game start we want to declare a variable to store the events. We’ll call it global.events and set it to 0.

Now we want a list of enums for events. Because we’re using binary operators, each item in the list must be a successive power of 2.

enum EVENTS
     {
         BORINGEVENT=1,
         COOLEVENT=2,
         SUPEREVENT=4,
         RUNNINGOUTOFNAMES=8
     }

To set an event as completed we just need to use bitwise or (|):

 global.events=global.events|EVENTS.BORINGEVENT;

This will set global.events=1, since EVENTS.BORINGEVENT=1.

We can set another event as completed in the same way:

global.events=global.events|EVENTS.SUPEREVENT;

So now global.events=5, but in binary this is 0101. Each event is a slot in binary. Now global.events=EVENTS.SUPEREVENT+EVENTS.BORINGEVENT.

We can use bitwise and (&) to check if an event has been completed. The following code block will store the status of BORINGEVENT to a local variable boringeventcompleted. If it has been flagged as completed, boringeventcompleted=EVENTS.BORINGEVENT, otherwise boringeventcompleted=0.

var boringeventcompleted=global.events&EVENTS.BORINGEVENT;

Lastly we may, under certain circumstances, want to set an event as not completed. For this we will use bitwise not (~):

global.events=global.events&~EVENTS.RUNNINGOUTOFNAMES;

Using these methods we can compactly store the status of many events in one integer. This immensely helps with organisation and saving game data.

This has potential for many other uses, such as tracking branching dialogue choices or keeping track of a player’s morality decisions.

Code blocks:

Initialise the events variable at game start:

global.events=0;

Set up enums – this code just needs to exist somewhere in the project, even if never referenced. Ensure all events are successive powers of 2:

enum EVENTS
     {
         BORINGEVENT=1,
         COOLEVENT=2,
         SUPEREVENT=4,
         RUNNINGOUTOFNAMES=8
     }

Mark an event as completed:

var event=EVENTS.BORINGEVENT;
global.events=global.events|event;

Check if an event has been completed – unlike before, this will set eventcompleted to either true or false:

var event=EVENTS.COOLEVENT;
var eventcompleted=false;
if (global.events&event==event)
    {
        eventcompleted=true;
    }

Alternatively you can use this, however it is a little less readable:

var event=EVENTS.COOLEVENT;
var eventcompleted=sign(global.events&event);

Mark event as not completed:

var event=EVENTS.SUPEREVENT;
global.events=global.events&~event;

Any code is free to use for however you see fit. Credit not needed but is appreciated. Feel free to send me your projects if you do make use of it!

Talk about this post and suggest new blog topics in my Community Discord!

If you like my work, consider supporting me on Ko-fi!