GGJ got me thinking that it would be great if developers did not have to worry about the communication aspects of their game and, instead, could focus on the actual game and this led me to try to create an API that would simplify this considerably. Enter the FaceValueHandler class.
Let’s go directly to a simple usage example:
#include "face_value_handler.h"
// We have a single piece of data we want to propagate, so it starts at offset 0.
#define OFFSET_GAME_MODE 0
// As we have a single piece of information, it is at index 0.
#define INDEX_GAME_MODE 0
void loop() {
// This creates a handler for a single piece of face value data (field), detects if it changed
// since the last loop iteration and, if did, automatically propagates it to all faces.
FaceValueHandler face_value_handler(nullptr, OFFSET_GAME_MODE);
// Now we get the (possibly updated above) game mode from any of the output faces.
// We use 0 here but could as well have used any other number.
byte game_mode = face_value_handler.GetOutputFieldValue(0, INDEX_GAME_MODE);
// Update the game mode in case the button was clicked.
if (buttonSingleClicked()) {
game_mode = (game_mode + 1) % 4;
// Change the output value for the game mode field in all output faces.
face_value_handler.SetOutputFieldValueOnAllFaces(INDEX_GAME_MODE,
game_mode);
}
// Simple Blink rendering that shows game modes as colors.
switch (game_mode) {
case 0:
setColor(RED);
break;
case 1:
setColor(YELLOW);
break;
case 2:
setColor(GREEN);
break;
case 3:
setColor(CYAN);
break;
}
// Before loop() returns, input face values will be cached and output face values will be
// set.
}
And that is it. This code is doing the automatic propagation of only the pieces of data (a single one in this example) that change in the input to the output.
No need to fiddle with bits. No need to explicitly set the output face values or to get input face values.
The code supports a callback for custom handling of fields, but I will write an example using it another time.
To use it, you just need to copy the .h and .cpp files from the repository below to the directory your .ino file is and "#include “face_value_handler.h” at the top of your .ino file. Then you can just instantiate it and call any methods you want.
Right now it is using a bit more storage than I think is reasonable, but I did not do any optimization pass yet so things should improve on later versions.
Let me know what you think!