DIXSON JOSE SEBASTIAN
Published © GPL3+

Smart dinning kiosk

An ESP32-powered restaurant tabletop kiosk featuring retro arcade games, randomized food trivia discounts, and order prep timers.

IntermediateFull instructions provided3 hours30
Smart dinning kiosk

Things used in this project

Hardware components

Seeed Studio XIAO ESP32S3 Sense
Seeed Studio XIAO ESP32S3 Sense
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Analog joystick (Generic)
×1
Jumper wires (generic)
Jumper wires (generic)
×1
LED (generic)
LED (generic)
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Smart Dining Kiosk - Circuit Schematic & Wiring Diagram

Circuit schematic and breadboard wiring diagram for the Smart Dining Kiosk, designed using Wokwi.

How to read/use it:
- Controller: Seeed Studio XIAO ESP32S3 Sense.
- Display: 0.96" I2C SSD1306 OLED connected to SDA (D4/GPIO5) and SCL (D5/GPIO6), powered via 3V3.
- Input: Two-axis analog joystick connected to D0 (VRx), D1 (VRy), and D2 (SW/Select Button with internal pull-up).
- Feedback LEDs: Green LED on D3 (Correct Answer / Success) and Red LED on D6 (Wrong Answer / Game Over), both wired to GND through 220Ω current-limiting resistors.
- Power: All modules share common 3.3V (VCC) and GND rails.

Code

Smart Dining Kiosk - Main Firmware (ESP32 / C++)

C/C++
This is the complete Arduino C++ firmware for the Smart Dining Kiosk running on a Seeed Studio XIAO ESP32S3 Sense.

What it does & how to use it:
- Order & Prep Tracking: Allows customers to select their food order (Biriyani, Porotta, Mandhi) and view estimated preparation times.
- Gamified Discounts: Generates a randomized 5-question food trivia quiz from an internal 15-question bank. Each correct answer awards a 1% bill discount.
- Arcade Games: Includes fully playable versions of Snake Xenzia, Dino Run, and a Lights-Out Reaction Time Test to entertain customers while waiting.
- Feedback System: Controls two indicator LEDs (Green on pin D3 for Correct/Success, Red on pin D6 for Wrong/Failure) and renders UI graphics on a 0.96" SSD1306 OLED display via I2C.
- Input & Control: Uses a 2-axis analog thumb joystick with built-in switch debouncing (via Bounce2 library) for menu navigation and gameplay.
  #include <Wire.h>
  #include <Adafruit_GFX.h>
  #include <Adafruit_SSD1306.h>
  #include <Bounce2.h>

  // ==========================================
  // OLED DISPLAY SETTINGS
  // ==========================================
  #define SCREEN_WIDTH 128
  #define SCREEN_HEIGHT 64
  #define OLED_RESET    -1 
  Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

  // ==========================================
  // HARDWARE PINS (UPDATED FOR 2 LEDS)
  // ==========================================
  #define JOY_X_PIN D0
  #define JOY_Y_PIN D1
  #define JOY_SW_PIN D2

  #define LED_CORRECT D3
  #define LED_WRONG D6

  Bounce2::Button joyButton = Bounce2::Button();

  // ==========================================
  // GAME STATE & VARIABLES
  // ==========================================
  enum GameState { WELCOME, FOOD_MENU, PREP_TIME, MENU, GAMES_MENU, INSTRUCTIONS, QUIZ, GAMEOVER, LEADERBOARD, REACTION_GAME, SNAKE_GAME, SNAKE_GAMEOVER, DINO_GAME, DINO_GAMEOVER };
  GameState currentState = WELCOME;

  // --- Menu Navigation ---
  int foodMenuSelection = 0;
  int mainMenuSelection = 0;     
  int gamesMenuSelection = 0;    

  // --- Food Data ---
  String foodItems[3] = {"Biriyani", "Porotta", "Mandhi"};
  int foodPrepTimes[3] = {20, 10, 25}; 
  int activePrepTime = 0;
  String activeFood = "";

  // --- Quiz Variables ---
  #define TOTAL_QUESTIONS 15
  int currentQuestion = 0;
  int quizScore = 0;
  int quizSelection = 0;
  int selectedQuestions[5]; 

  String allQuestions[TOTAL_QUESTIONS] = { 
    "What is a tomato?", "Main part of Guacamole?", "Which is a root veg?", "Sushi wrapper name?", "Not a type of pasta?",
    "What makes bread rise?", "Nut inside marzipan?", "Origin of French Fries?", "Main part of hummus?", "Tofu is made from?",
    "Spice making curry yellow", "Is a pumpkin a fruit?", "Most stolen food?", "Feta cheese is from?", "What is calamari?"
  };

  String allOptions[TOTAL_QUESTIONS][3] = { 
    {"Fruit", "Vegetable", "Meat"}, {"Tomato", "Avocado", "Lime"}, {"Spinach", "Carrot", "Celery"}, {"Nori", "Wasabi", "Mochi"}, {"Penne", "Ravioli", "Baguette"},
    {"Yeast", "Salt", "Sugar"}, {"Walnut", "Almond", "Cashew"}, {"France", "Belgium", "USA"}, {"Lentils", "Chickpeas", "Beans"}, {"Soy", "Wheat", "Milk"},
    {"Cumin", "Turmeric", "Clove"}, {"Yes", "No", "It's a root"}, {"Cheese", "Meat", "Bread"}, {"Italy", "Greece", "Spain"}, {"Squid", "Octopus", "Clam"}
  };

  int allCorrectAnswers[TOTAL_QUESTIONS] = {
    0, 1, 1, 0, 2, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0
  }; 

  // --- Reaction Game Variables ---
  unsigned long sequenceStartTime = 0;
  unsigned long waitStartTime = 0;
  unsigned long randomDelay = 0;
  unsigned long finalReactionTime = 0;
  int lightsOn = 0;
  int reactionSubState = 0; 

  // --- Snake Xenzia Variables ---
  int snakeX[64];
  int snakeY[64];
  int snakeLength = 3;
  int snakeDir = 1; 
  int foodX = 10, foodY = 10;
  unsigned long lastSnakeMove = 0;
  int snakeScore = 0;

  // --- Dino Run Variables ---
  float dinoY = 38;        
  float dinoVelocity = 0;  
  bool isJumping = false;
  int cactusX = 128;       
  int dinoScore = 0;

  // ==========================================
  // SETUP & UTILITIES
  // ==========================================
  // New function for the Welcome blinking pattern
  void playWelcomePattern() {
    for (int i = 0; i < 3; i++) {
      digitalWrite(LED_CORRECT, HIGH);
      digitalWrite(LED_WRONG, LOW);
      delay(150);
      digitalWrite(LED_CORRECT, LOW);
      digitalWrite(LED_WRONG, HIGH);
      delay(150);
    }
    digitalWrite(LED_WRONG, LOW); // Turn both off at the end
  }

  // Helper to turn off all LEDs cleanly
  void turnOffLEDs() {
    digitalWrite(LED_CORRECT, LOW);
    digitalWrite(LED_WRONG, LOW);
  }

  void setup() {
    Serial.begin(115200);
    randomSeed(analogRead(A3)); 

    pinMode(LED_CORRECT, OUTPUT);
    pinMode(LED_WRONG, OUTPUT);
    turnOffLEDs();

    joyButton.attach(JOY_SW_PIN, INPUT_PULLUP);
    joyButton.interval(15);
    joyButton.setPressedState(LOW);

    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
      for(;;); 
    }

    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(10, 25);
    display.println("SYSTEM BOOTING...");
    display.display();
    delay(1500); 

    // Play pattern before showing the first welcome screen
    playWelcomePattern(); 
  }

  // ==========================================
  // MAIN LOOP
  // ==========================================
  void loop() {
    joyButton.update();
    int joyX = analogRead(JOY_X_PIN);
    int joyY = analogRead(JOY_Y_PIN);

    switch (currentState) {
      case WELCOME:        handleWelcome();                break;
      case FOOD_MENU:      handleFoodMenu(joyY);           break;
      case PREP_TIME:      handlePrepTime(joyX);           break;
      case MENU:           handleMainMenu(joyY);           break;
      case GAMES_MENU:     handleGamesMenu(joyY);          break;
      case INSTRUCTIONS:   handleInstructions(joyX);       break;
      case QUIZ:           handleQuiz(joyX, joyY);         break;
      case GAMEOVER:       handleGameOver();               break;
      case LEADERBOARD:    handleLeaderboard(joyX);        break;
      case REACTION_GAME:  handleReactionGame();           break;
      case SNAKE_GAME:     handleSnakeGame(joyX, joyY);    break;
      case SNAKE_GAMEOVER: handleSnakeGameOver();          break;
      case DINO_GAME:      handleDinoGame();               break;
      case DINO_GAMEOVER:  handleDinoGameOver();           break;
    }
  }

  // ==========================================
  // STATE: WELCOME SCREEN
  // ==========================================
  void handleWelcome() {
    display.clearDisplay();
    display.setTextSize(2);
    display.setCursor(20, 10);
    display.println("WELCOME");
    
    display.setTextSize(1);
    display.setCursor(15, 35);
    display.println("To The Food Hub!");
    
    display.setCursor(10, 55);
    display.println("[Press to Order]");
    display.display();

    if (joyButton.pressed()) {
      foodMenuSelection = 0;
      currentState = FOOD_MENU;
    }
  }

  // ==========================================
  // STATE: FOOD SELECTION MENU
  // ==========================================
  void handleFoodMenu(int joyY) {
    if (joyY < 1000) {
      foodMenuSelection--;
      if (foodMenuSelection < 0) foodMenuSelection = 0;
      delay(200); 
    } else if (joyY > 3000) {
      foodMenuSelection++;
      if (foodMenuSelection > 3) foodMenuSelection = 3; 
      delay(200);
    }

    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Select Your Order:");
    display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
    
    for (int i = 0; i < 3; i++) {
      display.setCursor(10, 15 + (i * 12));
      if (foodMenuSelection == i) display.print(">");
      display.println(" " + foodItems[i]);
    }
    
    display.setCursor(10, 52);
    if (foodMenuSelection == 3) display.print(">");
    display.println(" <- Back");
    
    display.display();

    if (joyButton.pressed()) {
      if (foodMenuSelection == 3) {
        playWelcomePattern(); // Play pattern when returning to Welcome
        currentState = WELCOME;
      } else {
        activeFood = foodItems[foodMenuSelection];
        activePrepTime = foodPrepTimes[foodMenuSelection];
        currentState = PREP_TIME;
      }
    }
  }

  // ==========================================
  // STATE: ESTIMATED TIME SCREEN
  // ==========================================
  void handlePrepTime(int joyX) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Order Confirmed!");
    display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
    
    display.setCursor(0, 20);
    display.print("Preparing: "); 
    display.println(activeFood);

    display.setTextSize(2);
    display.setCursor(0, 35);
    display.print(activePrepTime);
    display.println(" mins");
    
    display.setTextSize(1);
    display.setCursor(0, 55);
    display.println("[< Back]  [Press Next]");
    
    display.display();

    if (joyButton.pressed()) currentState = MENU;
    if (joyX < 1000) { currentState = FOOD_MENU; delay(300); }
  }

  // ==========================================
  // STATE: THE MAIN MENU
  // ==========================================
  void handleMainMenu(int joyY) {
    if (joyY < 1000) {
      mainMenuSelection--;
      if (mainMenuSelection < 0) mainMenuSelection = 0;
      delay(200); 
    } else if (joyY > 3000) {
      mainMenuSelection++;
      if (mainMenuSelection > 3) mainMenuSelection = 3; 
      delay(200);
    }

    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Wait time: ");
    display.print(activePrepTime);
    display.println(" mins");
    display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
    
    display.setCursor(10, 18);
    if (mainMenuSelection == 0) display.print(">"); display.println(" Games");
    
    display.setCursor(10, 30);
    if (mainMenuSelection == 1) display.print(">"); display.println(" Quizzes");
    
    display.setCursor(10, 42);
    if (mainMenuSelection == 2) display.print(">"); display.println(" Leaderboard");
    
    display.setCursor(10, 54);
    if (mainMenuSelection == 3) display.print(">"); display.println(" <- Back to Food");
    
    display.display();

    if (joyButton.pressed()) {
      if (mainMenuSelection == 0)      { gamesMenuSelection = 0; currentState = GAMES_MENU; }
      else if (mainMenuSelection == 1) currentState = INSTRUCTIONS;
      else if (mainMenuSelection == 2) currentState = LEADERBOARD;
      else if (mainMenuSelection == 3) currentState = FOOD_MENU; 
    }
  }

  // ==========================================
  // STATE: THE GAMES SUB-MENU
  // ==========================================
  void handleGamesMenu(int joyY) {
    if (joyY < 1000) {
      gamesMenuSelection--;
      if (gamesMenuSelection < 0) gamesMenuSelection = 0;
      delay(200); 
    } else if (joyY > 3000) {
      gamesMenuSelection++;
      if (gamesMenuSelection > 3) gamesMenuSelection = 3; 
      delay(200);
    }

    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("--- ARCADE ---");
    display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
    
    display.setCursor(10, 15);
    if (gamesMenuSelection == 0) display.print(">"); display.println(" Snake Xenzia");
    
    display.setCursor(10, 27);
    if (gamesMenuSelection == 1) display.print(">"); display.println(" Reaction Test");

    display.setCursor(10, 39);
    if (gamesMenuSelection == 2) display.print(">"); display.println(" Dino Run");
    
    display.setCursor(10, 51);
    if (gamesMenuSelection == 3) display.print(">"); display.println(" <- Back to Main");
    
    display.display();

    if (joyButton.pressed()) {
      turnOffLEDs();
      
      if (gamesMenuSelection == 0)      initSnake();
      else if (gamesMenuSelection == 1) { reactionSubState = 0; currentState = REACTION_GAME; }
      else if (gamesMenuSelection == 2) initDino();
      else if (gamesMenuSelection == 3) currentState = MENU; 
    }
  }

  // ==========================================
  // STATE: QUIZ INSTRUCTIONS
  // ==========================================
  void handleInstructions(int joyX) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("QUIZ RULES:");
    display.println("- 5 Questions");
    display.println("- 1% discount per");
    display.println("  correct answer!");
    display.setCursor(0, 50);
    display.println("[< Back] [Press Start]");
    display.display();

    if (joyButton.pressed()) {
      quizScore = 0; 
      currentQuestion = 0; 
      quizSelection = 0;
      
      for (int i = 0; i < 5; i++) {
        bool isDuplicate;
        int candidate;
        do {
          isDuplicate = false;
          candidate = random(0, TOTAL_QUESTIONS);
          for (int j = 0; j < i; j++) {
            if (selectedQuestions[j] == candidate) {
              isDuplicate = true;
              break;
            }
          }
        } while (isDuplicate);
        selectedQuestions[i] = candidate;
      }
      
      currentState = QUIZ;
    }
    
    if (joyX < 1000) { currentState = MENU; delay(300); }
  }

  // ==========================================
  // STATE: THE QUIZ LOOP
  // ==========================================
  void handleQuiz(int joyX, int joyY) {
    if (joyX < 1000) { currentState = MENU; delay(300); return; }

    if (joyY < 1000) {
      quizSelection--;
      if (quizSelection < 0) quizSelection = 0;
      delay(200);
    } else if (joyY > 3000) {
      quizSelection++;
      if (quizSelection > 2) quizSelection = 2;
      delay(200);
    }

    int actualQIndex = selectedQuestions[currentQuestion];

    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Q"); display.print(currentQuestion + 1); display.print(": ");
    display.println(allQuestions[actualQIndex]);
    display.drawLine(0, 17, 128, 17, SSD1306_WHITE);

    for (int i = 0; i < 3; i++) {
      display.setCursor(10, 25 + (i * 12));
      if (quizSelection == i) display.print(">");
      display.println(allOptions[actualQIndex][i]);
    }
    display.display();

    if (joyButton.pressed()) {
      if (quizSelection == allCorrectAnswers[actualQIndex]) {
        // Blink CORRECT LED
        digitalWrite(LED_CORRECT, HIGH); 
        delay(300); 
        digitalWrite(LED_CORRECT, LOW);
        quizScore++;
      } else {
        // Blink WRONG LED
        digitalWrite(LED_WRONG, HIGH); 
        delay(300); 
        digitalWrite(LED_WRONG, LOW);
      }
      
      currentQuestion++;
      quizSelection = 0;
      if (currentQuestion >= 5) currentState = GAMEOVER;
    }
  }

  // ==========================================
  // STATE: QUIZ RESULTS
  // ==========================================
  void handleGameOver() {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("QUIZ COMPLETE!");
    display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
    
    display.setTextSize(2);
    display.setCursor(0, 20);
    display.print("Score: "); display.print(quizScore); display.println("/5");
    display.setTextSize(1);
    display.setCursor(0, 45);
    display.print("You won a "); display.print(quizScore); display.println("% discount!");
    
    display.setCursor(0, 55); display.println("[Press for Leaderboard]");
    display.display();

    if (joyButton.pressed()) currentState = LEADERBOARD;
  }

  // ==========================================
  // STATE: LEADERBOARD
  // ==========================================
  void handleLeaderboard(int joyX) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("--- LEADERBOARD ---");
    display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
    
    display.setCursor(10, 15); display.println("1. Table 4   - 5/5");
    display.setCursor(10, 25); display.println("2. Table 9   - 4/5");
    display.setCursor(10, 35); display.print("3. YOUR TEAM - "); display.print(quizScore); display.println("/5");
    
    display.setCursor(0, 55); display.println("[< Back] [Press Reset]");
    display.display();

    if (joyButton.pressed()) {
      turnOffLEDs();
      mainMenuSelection = 0; 
      playWelcomePattern(); // Play pattern when restarting flow
      currentState = WELCOME;
    }
    if (joyX < 1000) { currentState = MENU; delay(300); }
  }

  // ==========================================
  // ARCADE GAMES (Snake, Dino, Reaction)
  // ==========================================

  void initDino() {
    dinoY = 38; dinoVelocity = 0; isJumping = false; cactusX = 128; dinoScore = 0;
    currentState = DINO_GAME;
  }

  void handleDinoGame() {
    if (joyButton.pressed() && !isJumping) { dinoVelocity = -5.5; isJumping = true; }
    dinoVelocity += 0.6; dinoY += dinoVelocity;
    if (dinoY >= 38) { dinoY = 38; dinoVelocity = 0; isJumping = false; }
    cactusX -= 4; 
    if (cactusX < -10) {
      cactusX = 128; dinoScore++;   
      // Blink Correct LED for scoring a point
      digitalWrite(LED_CORRECT, HIGH); delay(20); digitalWrite(LED_CORRECT, LOW);
    }
    if (cactusX < 24 && cactusX > 6 && dinoY > 26) { currentState = DINO_GAMEOVER; return; }

    display.clearDisplay();
    display.setCursor(100, 0); display.print(dinoScore);
    display.drawLine(0, 50, 128, 50, SSD1306_WHITE);
    display.fillRect(cactusX, 36, 6, 14, SSD1306_WHITE); display.fillRect(cactusX - 3, 40, 3, 6, SSD1306_WHITE);
    int intY = (int)dinoY;
    display.fillRect(14, intY, 10, 8, SSD1306_WHITE); display.drawPixel(20, intY + 2, SSD1306_BLACK); display.fillRect(10, intY + 8, 12, 10, SSD1306_WHITE);  
    
    if (!isJumping && (millis() / 100) % 2 == 0) {
      display.drawLine(12, intY + 18, 12, intY + 22, SSD1306_WHITE); display.drawLine(16, intY + 18, 18, intY + 20, SSD1306_WHITE); 
    } else {
      display.drawLine(12, intY + 18, 10, intY + 20, SSD1306_WHITE); display.drawLine(18, intY + 18, 18, intY + 22, SSD1306_WHITE); 
    }
    display.display(); delay(20); 
  }

  void handleDinoGameOver() {
    display.clearDisplay(); display.setCursor(0, 0); display.println("EXTINCTION!"); display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
    display.setTextSize(2); display.setCursor(0, 25); display.print("Score: "); display.println(dinoScore); display.setTextSize(1);
    display.setCursor(0, 50); display.println("[Press to Menu]"); display.display();
    if (joyButton.pressed()) { gamesMenuSelection = 0; currentState = GAMES_MENU; }
  }

  void initSnake() {
    snakeLength = 3; snakeDir = 1; snakeScore = 0;
    snakeX[0] = 16; snakeY[0] = 8; snakeX[1] = 15; snakeY[1] = 8; snakeX[2] = 14; snakeY[2] = 8;
    foodX = random(2, 30); foodY = random(2, 14); currentState = SNAKE_GAME;
  }

  void handleSnakeGame(int joyX, int joyY) {
    if (joyY < 1000 && snakeDir != 2) snakeDir = 0;      
    else if (joyX > 3000 && snakeDir != 3) snakeDir = 1; 
    else if (joyY > 3000 && snakeDir != 0) snakeDir = 2; 
    else if (joyX < 1000 && snakeDir != 1) snakeDir = 3; 

    if (millis() - lastSnakeMove > 150) { 
      lastSnakeMove = millis();
      for (int i = snakeLength - 1; i > 0; i--) { snakeX[i] = snakeX[i - 1]; snakeY[i] = snakeY[i - 1]; }
      if (snakeDir == 0) snakeY[0]--; if (snakeDir == 1) snakeX[0]++; if (snakeDir == 2) snakeY[0]++; if (snakeDir == 3) snakeX[0]--;

      if (snakeX[0] < 0 || snakeX[0] >= 32 || snakeY[0] < 0 || snakeY[0] >= 16) { currentState = SNAKE_GAMEOVER; return; }
      for (int i = 1; i < snakeLength; i++) { if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) { currentState = SNAKE_GAMEOVER; return; } }
      if (snakeX[0] == foodX && snakeY[0] == foodY) {
        if (snakeLength < 64) snakeLength++; snakeScore++;
        foodX = random(1, 31); foodY = random(1, 15);
        // Blink Correct LED for eating food
        digitalWrite(LED_CORRECT, HIGH); delay(30); digitalWrite(LED_CORRECT, LOW);
      }
    }

    display.clearDisplay(); display.fillRect(foodX * 4, foodY * 4, 4, 4, SSD1306_WHITE);
    for (int i = 0; i < snakeLength; i++) { display.fillRect(snakeX[i] * 4, snakeY[i] * 4, 4, 4, SSD1306_WHITE); }
    display.display();
  }

  void handleSnakeGameOver() {
    display.clearDisplay(); display.setCursor(0, 0); display.println("SNAKE CRASHED!"); display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
    display.setTextSize(2); display.setCursor(0, 25); display.print("Apples: "); display.println(snakeScore); display.setTextSize(1);
    display.setCursor(0, 50); display.println("[Press to Menu]"); display.display();
    if (joyButton.pressed()) { gamesMenuSelection = 0; currentState = GAMES_MENU; }
  }

  void handleReactionGame() {
    switch (reactionSubState) {
      case 0: 
        display.clearDisplay(); display.setCursor(0, 0); display.println("--- LIGHTS OUT ---");
        display.println("Press the button"); display.println("the exact moment"); display.println("both LEDs go dark!");
        display.setCursor(0, 50); display.println("[Press to Ready]"); display.display();
        if (joyButton.pressed()) { reactionSubState = 1; lightsOn = 0; sequenceStartTime = millis(); }
        break;
      case 1: 
        display.clearDisplay(); display.setCursor(30, 25); display.setTextSize(2); display.println("READY"); display.setTextSize(1); display.display();
        if (millis() - sequenceStartTime > 1000) {
          if (lightsOn == 0) { 
            digitalWrite(LED_CORRECT, HIGH); lightsOn++; sequenceStartTime = millis(); 
          } 
          else if (lightsOn == 1) { 
            digitalWrite(LED_WRONG, HIGH); lightsOn++; sequenceStartTime = millis(); 
          } 
          else { 
            reactionSubState = 2; randomDelay = random(500, 3500); waitStartTime = millis(); 
          }
        }
        if (joyButton.pressed()) reactionSubState = 4; 
        break;
      case 2: 
        if (millis() - waitStartTime > randomDelay) {
          turnOffLEDs();
          sequenceStartTime = millis(); reactionSubState = 3;
        }
        if (joyButton.pressed()) reactionSubState = 4;
        break;
      case 3: 
        display.clearDisplay(); display.setCursor(50, 25); display.setTextSize(2); display.println("GO!"); display.setTextSize(1); display.display();
        if (joyButton.pressed()) { finalReactionTime = millis() - sequenceStartTime; reactionSubState = 5; }
        break;
      case 4: 
        turnOffLEDs();
        display.clearDisplay(); display.setCursor(10, 20); display.setTextSize(2); display.println("JUMP START"); display.setTextSize(1);
        display.setCursor(0, 50); display.println("[Press to Menu]"); display.display();
        if (joyButton.pressed()) currentState = GAMES_MENU;
        break;
      case 5: 
        display.clearDisplay(); display.setCursor(0, 0); display.println("REACTION TIME:"); display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
        display.setCursor(0, 25); display.setTextSize(2); display.print(finalReactionTime); display.println(" ms"); display.setTextSize(1);
        display.setCursor(0, 50); display.println("[Press to Menu]"); display.display();
        if (joyButton.pressed()) currentState = GAMES_MENU;
        break;
    }
  }

Credits

DIXSON JOSE SEBASTIAN
2 projects • 1 follower

Comments