Project 7.02 Reaction Game Using OLED

In this project we will make a reaction time game! The game will be able to keep track of the current record in milliseconds and will even be able to tell if the user cheated!

Project Code:

////////////////////////////////////////////////////////////////////////
// 7.02 - Reaction Game Using The OLED

#include <Adafruit_SSD1306.h>
#include <splash.h>

byte screenWidth = 128;
byte screenHeight = 64;
byte screenAddress = 0x3C;

byte LED1 = 13;

bool pressed = LOW;
byte SW1 = 1;
byte SW2 = 0;

int timesPlayed = 0;
long record = 0;

bool cheated = false;

Adafruit_SSD1306 display(screenWidth, screenHeight, &Wire);

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, screenAddress);
  display.setTextColor(SSD1306_WHITE); 
  display.setTextSize(2);

  pinMode(LED1, OUTPUT);

  pinMode(SW1, INPUT);
  pinMode(SW2, INPUT);
}

void loop() {
  cheated = false;

  while (digitalRead(SW1) != pressed) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Press SW1");
    display.println("To Play!");

    if (timesPlayed != 0) {
      display.println("Record: ");
      display.print(record);
      display.println(" ms");
    }
    display.display();
  }

  digitalWrite(LED1, HIGH);
  int waitTime = random(1000, 4001);
  long startWaitTime = millis();

  while (waitTime + startWaitTime > millis()) {
    if (digitalRead(SW2) == pressed) {
      cheated = true;
      break;
    }
  }

  digitalWrite(LED1, LOW);

  if (cheated != true) {
    long startTime = millis();

    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Press the ");
    display.println("button!");
    display.display();
    
    while (digitalRead(SW2) != pressed) {
      ;
    }

    long endTime = millis();
    long totalTime = endTime - startTime;

    if (timesPlayed == 0) {
      record = totalTime;
    }
    else if (totalTime < record) {
      record = totalTime;
    }

    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("You took");
    display.print(totalTime);
    display.println(" ms");
    display.println("to react!");
    display.display();

    timesPlayed++;

  }
  else {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("You");
    display.println("cheated!");
    display.setTextSize(4);
    display.println(":(");
    display.setTextSize(2); 
    display.display();
  }
  
  delay(3000);
}
////////////////////////////////////////////////////////////////////////

*If you’re copying and pasting the code, or typing from scratch, delete everything out of a new Arduino sketch and paste / type in the above text.

This program is a bit longer than the others, but don’t worry it’ll all be broken down.

Let’s define our game:

Our game will test reaction time by turning on an LED for a random amount of time, having the player press a button when that LED turns off, timing how long after the LED turned off that the player pressed the button, and displaying that on a screen. It would also be nice if we could keep track of the best reaction time.

As a bonus project, see if you can get the Piezo to Buzz when the user cheats!

Let’s break that down a little more:

  • Use LED1 as the reaction LED

  • Turn LED1 on for a random time between 1 and 4 seconds

  • Use the left button to start the game

  • Use the right button to react to the LED turning off

  • Keep track of the time from when the LED turns off to when the button is pressed

  • Display that time on the screen

  • Keep track of the best reaction time

Now that we have defined the game, we can program it. First things first, we need to include the proper libraries to use the OLED.

#include <Adafruit_SSD1306.h>
#include <splash.h>

Next, we define the height, width, and address of the OLED.

byte screenWidth = 128;
byte screenHeight = 64;
byte screenAddress = 0x3C;

Then we need to declare some additional variables in our code to define things like the LED that will be used as the reaction indicator, the buttons that will be used, and some general variables that will be used to play the game.

byte screenWidth = 128;
byte screenHeight = 64;
byte screenAddress = 0x3C;

byte LED1 = 13;

bool pressed = LOW;
byte SW1 = 1;
byte SW2 = 0;   

These three variables will be used to record the number of times the game has been played, the record and if the player has cheated.

int timesPlayed = 0;
long record = 0;

bool cheated = false;

Here we just include the constructor for the OLED.

Adafruit_SSD1306 display(screenWidth, screenHeight, &Wire);

In the setup() function we need to setup our pinModes and OLED. The buttons will be INPUTs and the LED will be an OUTPUT.

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, screenAddress);
  display.setTextColor(SSD1306_WHITE); 
  display.setTextSize(2);

  pinMode(LED1, OUTPUT);

  pinMode(SW1, INPUT);
  pinMode(SW2, INPUT);
}

Next in the loop() function, we first need to reset the cheated variable before we play the game.

cheated = false;

Then we need to wait until the user presses the play button. We can wait by using a while-loop.

while (digitalRead(SW1) != pressed) {

While the program waits for the user to press the button it can print the “Menu” screen. The menu screen prompts the player to play by pressing SW1.

display.clearDisplay();
display.setCursor(0, 0);
display.println("Press SW1");
display.println("To Play!");

This screen is also where the record will be printed. There is no point in printing a record on this screen if the game has not been played, because there is no record. So, by using the timesPlayed variable we can check if the game has been played. If so, print the record.

if (timesPlayed != 0) {
  display.println("Record: ");
  display.print(record);
  display.println(" ms");
}

Now that we have loaded the data into the OLED, we need to display it.

  display.display();
}

Once the button has been pressed the program moves on from the while-loop.

At this point we know the player is ready to play the game so turn the LED on.

digitalWrite(LED1, HIGH);

Next, we need to get a random time between 1 and 4 seconds to keep the LED on for. This can be done with the random function. It will return a random value between the first number passed and the second number passed minus 1.

int waitTime = random(1000, 4001);

If we are going to wait for some time from now, then we need to know what time it is now. We can get that by using the millis() funciton.

long startWaitTime = millis();

To wait we need to keep checking the time to see if it’s waitTime past the startWaitTime. For example, if the startWaitTime was 1567 milliseconds and the waitTime was 3000 we need to wait until millis() returns 4567 to move on. startWaitTime + waitTime needs to be less than what millis() returns.

while (waitTime + startWaitTime > millis()) {

While we are waiting for the time to elapse the LED is still on. If the player presses the button while the LED is on that is considered cheating. So, if the player presses the button while we are in this while-loop then they are cheating. We can tell if they press the button by monitoring it. In the loop we can put an if statement to check and see if the button is being pressed.

if (digitalRead(SW2) == pressed) {

If the button is being pressed, we set the cheated variable to true.

cheated = true;

Then we use the keyword “break” to leave the while-loop. break can be used to break out of loops completely. There is no need to stay in the loop waiting if the player cheated, so we can move on.

    break;
  }
}

Next, we can turn the LED off. At this point the player has either cheated of the time has properly elapsed.

digitalWrite(LED1, LOW);

After the LED is off, if the player did not cheat, we need to record the time that the LED turned off at.

if (cheated != true) {
  long startTime = millis();

Then we need to prompt the user to press the button (because the LED is off).

display.clearDisplay();
display.setCursor(0, 0);
display.println("Press the ");
display.println("button!");
display.display();

We then need to wait for the player to press SW2 which indicates a reaction.

while (digitalRead(SW2) != pressed) {
  ;
}

Once the player has pressed the button the while-loop breaks. We need to record that time with millis().

long endTime = millis();

To find out the total time it took from the LED turning off to when the player pressed the button, we have to subtract the time when the LED turned off from the time the player pressed the button.

long totalTime = endTime - startTime;

Then we check to see if this is the first time the player has played. 

if (timesPlayed == 0) {

If it is the first time, we set the record equal to the totalTime.

  record = totalTime;
}

If it is not the first time, then we check to see if the totalTime is less than the current record.

else if (totalTime < record) {

If it is, then that’s the new record time.

  record = totalTime;
}

We can then display the time the player took to react on the OLED.

display.clearDisplay();
display.setCursor(0, 0);
display.println("You took");
display.print(totalTime);
display.println(" ms");
display.println("to react!");
display.display();

Then we need to increment the timesPlayed variable to indicate that it is not the first time playing the game later.

timesPlayed++;

If the player cheated, we need to display that on the OLED.

else {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("You");
  display.println("cheated!");
  display.setTextSize(4);
  display.println(":(");
  display.setTextSize(2); 
  display.display();
}

After either case (cheated or not), we need to delay for three seconds to let the player see their time or see that they cheated.

delay(3000);
Previous
Previous

Project 7.03 Drawing Shapes with the OLED

Next
Next

Project 7.01 Writing Text to the Screen