Basic Communication Tutorial

We’ve talked about displays and we’ve talked about button interactions, so the only big thing we’ve got left to discuss is communication. Blinks, as you know can talk to each other. It’s kinda what makes them a big deal, and also what makes them so unique to develop for. Communication is handled with a few different commands, so we’ll build something really simple to show you how to use them. Let’s start by doing the absolute bare minimum: sensing our neighbors.

Create a script, then put in this code:

void loop() {
  FOREACH_FACE(f) {//check every face
    if (isValueReceivedOnFaceExpired(f)) {//no one there
      setColorOnFace(BLUE, f);
    } else {//someone there
      setColorOnFace(WHITE, f);
    }
  }
}

Before I explain what this does, install in on a few Blinks and connect them together in a few different ways.

What’s happening here is that every frame we’re checking each face and asking a simple question: have I received data on this face recently? The command “isValueReceivedOnFaceExpired()” returns true if that face has not received new information recently (the exact amount of time is unimportant and very small). If it returns false, it means that there is no neighbor on that face. So in our code, we display blue lights on our empty faces, and white one faces with neighbors. Pretty simple stuff.

But you probably want to do more than sense neighbors. Most games involve sending information between Blinks, and to do that we’ll need to both send and receive data using three different commands. First we’ll cover sending because it’s oddly similar to something we already know: display code. The commands “setValueSentOnAllFaces()” and “setValueSentOnFace()” work basically how you’d imagine. One sets a value to communicate on all faces, and the other sets a value on one particular face.

I want to take a second before we dive in to mention something very important about this form of communication - it can only communicate integer values between 0 and 63. Why this is the case and how you can work around this are discussions for another time (though I link to one of those times at the bottom) but for now, just keep that in mind when doing basic communication development. Now where were we…

Before we actually put this code in place, let’s discuss what we want it to do. We’re going to create a script that gives each Blink a specific lit face. When two Blinks are connected by that face, the entire Blink will light up. Our first step will be to set up the special face both visually and in terms of data sent. Our setup will look like this:

void setup() {
  setValueSentOnAllFaces(0);
  setValueSentOnFace(1, 0);
}

And our loop will now look like this (after we delete the code we had in there):

void loop() {
  //each frame we'll check to see if we've made a correct connection
  bool isConnectedCorrectly = false;

  //now we set the display
  if (isConnectedCorrectly) {
    setColor(MAGENTA);
  } else {
    setColor(OFF);
  }

  //always set the special face to white regardless
  setColorOnFace(WHITE, 0);
}

You could, if you want, install this, but it won’t really do anything. You’ll have a mostly off Blink with one light on. In order to use the information being sent by other Blinks, we also need to be listening. This is where the “getLastValueReceivedOnFace()” command comes into play. Let’s use it to check the data being received on our special face.

  //each frame we'll check to see if we've made a correct connection
  bool isConnectedCorrectly = false;
  if (getLastValueReceivedOnFace(0) == 1) {
    isConnectedCorrectly = true;
  }

The getLastValueReceivedOnFace() command returns a value, in this case either a 1 or a 0, because that’s the only values other Blinks will be broadcasting in this script. Install this on two or more Blinks to see them light up magenta when correctly connected.

But beware: this isn’t that well coded. You’ll notice that if you connect another Blink correctly and then remove it, they stay lit until an incorrect connection is made. Why? Well, look at the phrasing of the command - it just asks for “last value,” and doesn’t specify that it’s current. This is where our old friend “isValueReceivedOnFaceExpired()” comes into play. Let’s add a little extra check to our listener:

  if (!isValueReceivedOnFaceExpired(0)) { //a neighbor!
    if (getLastValueReceivedOnFace(0) == 1) {
      isConnectedCorrectly = true;
    }
  }

And that should do it. Now we are checking both that we have a neighbor and what it’s broadcasting. Install this on some Blinks and you’ll get the behavior we outlined at the top. Here’s the full code for reference:

void setup() {
  setValueSentOnAllFaces(0);
  setValueSentOnFace(1, 0);
}

void loop() {
  //each frame we'll check to see if we've made a correct connection
  bool isConnectedCorrectly = false;
  if (!isValueReceivedOnFaceExpired(0)) { //a neighbor!
    if (getLastValueReceivedOnFace(0) == 1) {
      isConnectedCorrectly = true;
    }
  }

  //now we set the display
  if (isConnectedCorrectly) {
    setColor(MAGENTA);
  } else {
    setColor(OFF);
  }

  //always set the special face to white regardless
  setColorOnFace(WHITE, 0);
}

Communication can be as simple as that. For examples of games with really simple communication, check out the code for Fracture, which is not terribly different than what we’ve done here. You could even check out Berry, which is a game that doesn’t technically require communication, but uses some neighbor sensing to adjust some graphics.

But for the most part, you’re going to want to do more with communication than sense basic things about your neighbors. You’ll want to be sending complex signals across the entire field, or communicating intensely with a particular neighbor or set of neighbors. Games like Zen Flow or Astro are good examples of more complex communication.

If you want to see one of our best practices for complex communication, you can check out the “Safely Sending Signals” tutorials we created. Also, if you go digging around in the documentation, or are looking at code for Speed Racer or Puzzle 101, you’ll notice these things called “datagrams.” Datagrams are a form of Blink-to-Blink communication that work totally differently than the communication we’ve used here, and require a different set of commands. A tutorial for that is forthcoming, but I’ll swing back into here and edit in a link later.

2 Likes