Close
0%
0%

Confusion alternative controller

Our project is to reproduce the platform game named confusion in an arcade form

Public Chat
Similar projects worth following
This interactive Arduino game combines reflexes, logic and speed to provide a fun and stimulating experience. It uses LEDs of different colours, buttons, a potentiometer and an LCD screen to create an engaging game mechanic.

Game theme:

The player must react quickly to combinations of two LEDs that light up randomly. Each combination requires a specific action, such as pressing a specific button or manipulating a wheel and a lever.






Game rules

Objective of the game :

Accumulate as many points as possible before the timer (30 seconds) runs out.
General operation:

Two LEDs light up simultaneously, one on each row.
Your aim is to perform the correct action according to the colours of the LEDs lit up.
If you perform the wrong action, the game will penalise you by displaying the LEDs briefly before starting a new round.
Correct actions according to colour combinations :

Two yellow LEDs: Press the two special yellow buttons simultaneously or turn the potentiometer significantly.
Two blue LEDs: Press the special blue button.
Two red LEDs: Turn the potentiometer hard enough (> 100).
Mixed combinations (of two different colours) :
Yellow + Red: Press the blue button.
Blue + Yellow: Press the red button.
Blue + Red: Press the yellow button.
Penalties :

Performing an incorrect action (pressing an unassociated button or turning the potentiometer when not requested) is considered an error.
Scoring:

A correct answer earns you a score based on your speed:
300 points maximum for an immediate answer.
The score decreases with reaction time (10 ms = -1 point).
The score is updated in real time on the LCD screen.
Display on the LCD screen :

The top line shows the time remaining.
The last line displays your current score.
End of game:

When the time runs out, the game stops.
The final score is displayed for 10 seconds before the game restarts with the score and timer reset.
Good luck and be quick to maximise your score!

IMG_2050.mov

quicktime - 2.28 MB - 12/16/2024 at 20:51

Download

side2.dxf

files for the wood cut

AutoCAD DXF - 2.94 kB - 12/03/2024 at 10:32

Download

front parts.dxf

files for the wood cut

AutoCAD DXF - 2.55 kB - 12/03/2024 at 10:32

Download

front 2.dxf

files for the wood cut

AutoCAD DXF - 5.10 kB - 12/03/2024 at 10:32

Download

upperboard.dxf

files for the wood cut

AutoCAD DXF - 3.13 kB - 12/03/2024 at 10:32

Download

View all 8 files

  • 1 × arduino card
  • 6 × buttons
  • 1 × Potentiometer
  • 6 × LED Fiber Optics / Emitters
  • 1 × Lever Switches and Relays / Switches

View all 8 components

  • Blog of the game

    dacshayan12/17/2024 at 10:21 0 comments

    October 15 - Session 1: Project Kickoff

    • Session Objectives:
      • Understand the project goals and expectations.
      • Decide on the main features of the game (interaction with LEDs, buttons, potentiometer, LCD screen).
      • Define team roles.
    • Achievements:
      • Explored the available electronic components (6 LEDs, 3 buttons, potentiometer, LCD I2C screen).
      • Tested all components to ensure they worked correctly.
      • Discussed game rules: random combinations, score management, and timing.
    • Next Steps: Build a first prototype with LEDs lighting up and responding via the buttons.

    October 22 - Session 2: First Game Mechanics

    • Session Objectives:
      • Program the basic logic for the LEDs (lighting up two random LEDs).
      • Implement initial rules for responding using the buttons.
    • Achievements:
      • Created a function to generate random LED combinations.
      • Implemented specific rules:
        • Two red LEDs = turn the potentiometer.
        • Two yellow LEDs = perform a specific action with two buttons.
      • Tested button responses to ensure they matched the LED combinations.
    • Next Steps: Integrate a timer to limit the duration of each round.

    October 29 - Session 3: Adding Time Management

    • Session Objectives:
      • Program a countdown timer for each round.
      • Integrate the LCD screen to display the remaining time and test its functionality.
    • Achievements:
      • Created a countdown timer that updates every second.
      • Integrated the LCD screen: displayed the timer and ran initial tests to show the score.
      • Tested automatic transitions between rounds after a response.
    • Next Steps: Add special actions to make the game more dynamic.

    November 5 - Session 4: Special Actions and Debugging

    • Session Objectives:
      • Add specific actions for certain combinations (potentiometer, special blue button).
      • Detect and fix button-related bugs.
    • Achievements:
      • Programmed the following actions:
        • Turn the potentiometer to validate yellow and red combinations.
        • Use a special button for blue combinations.
      • Fixed errors in button interruptions caused by simultaneous detections.
    • Next Steps: Integrate a scoring system based on reaction time.

    November 12 - Session 5: Scoring System and Display Construction

    • Session Objectives:
      • Build the physical display for the game, including interactive components.
      • Implement a scoring system based on reaction time.
      • Add a function to reset the game after each round or at the end of a game.
    • Achievements:
      • Constructed a rotating wheel and a lever for the potentiometer using Fusion 360 for 3D modeling:
        • The wheel was designed to rotate easily while being comfortable to grip.
        • The lever added a tactile interaction for triggering blue LED responses.
      • Designed and laser-cut a wooden display to house the game elements.
        • The display included slots for the LEDs, buttons, and the LCD screen.
        • Used plywood for a clean and minimalist finish.
      • Scoring system:
        • Reduced points based on response time (maximum of 300 points per round).
      • Created a full reset function: turned off LEDs, reset the timer, and updated the LCD screen.
    • Next Steps: Conduct full tests to identify bugs and improve game fluidity.

    November 19 - Session 6: Testing and Debugging

    • Session Objectives:
      • Perform intensive testing of the complete game to find bugs.
      • Fix synchronization errors between LEDs and buttons.
      • Integrate visual effects to signal correct and incorrect responses.
      • Perfect the logic for randomly changing LED combinations.
    • Achievements:
      • Fixed several issues:
        • Incorrect simultaneous detection of multiple buttons.
        • LED combinations not matching the intended actions.
      • Adjusted timings to improve smooth transitions between rounds.
      • Added a blinking effect for all LEDs after a correct response.
      • Fixed transitions to ensure smooth and quick display of new rounds.
    • Next Steps: Make adjustments to improve the user experience with the potentiometer. 

    December 3 - Session 7: Adjustments and Final Tests

    • Session Objectives:
      • Adjust detection thresholds for the potentiometer.
      • Perform final tests with complete game sessions.
    • Achievements:
      • Fine-tuned rotation thresholds for red and yellow combinations.
      • Comprehensive...
    Read more »

View project log

  • 1
    Code for our game
    #include <LiquidCrystal_I2C.h>
    
    // Définition de l'adresse I2C de l'écran LCD
    LiquidCrystal_I2C lcd(0x27, 20, 4);
    
    unsigned long previousMillis = 0;  // Stocke le dernier moment où l'écran a été mis à jour
    unsigned long interval = 1000;     // Intervalle de mise à jour du timer (1 seconde)
    int timer = 30;                   // Timer commençant à 100 secondes
    
    // Variables de jeu
    const int ledBlue1 = 2;
    const int ledBlue2 = 3;
    const int ledRed1 = 4;
    const int ledRed2 = 5;
    const int ledYellow1 = 6;
    const int ledYellow2 = 7;
    
    const int buttonBlue = 8;
    const int buttonRed = 9;
    const int buttonYellow = 10;
    
    const int buttonSpecialYellow1 = 11;
    const int buttonSpecialYellow2 = 12;
    const int buttonSpecialBlue = 13;
    
    const int potPin = A0;  // Pin pour le potentiomètre
    
    int currentLed1, currentLed2;
    int prevPotValue, potValue;  // Valeur précédente du potentiomètre
    int potThreshold = 50;  // Seuil pour une rotation significative du potentiomètre
    
    // Variables de score
    int score = 0;  // Score initial
    unsigned long lastResponseTime = 0; // Temps de réponse pour le calcul du score
    
    void setup() {
      lcd.init();              // Initialisation de l'écran LCD
      lcd.clear();             // Effacer l'écran
      lcd.backlight();         // Allumer le rétroéclairage
    
      lcd.setCursor(0, 0);     // Définir le curseur à la première ligne
      lcd.print("Time: ");     // Afficher le texte "Time:"
        lcd.setCursor(0, 3);     // Définir le curseur pour afficher le score
      lcd.print("Score: 0");
    
      pinMode(ledBlue1, OUTPUT);
      pinMode(ledBlue2, OUTPUT);
      pinMode(ledRed1, OUTPUT);
      pinMode(ledRed2, OUTPUT);
      pinMode(ledYellow1, OUTPUT);
      pinMode(ledYellow2, OUTPUT);
    
      pinMode(buttonBlue, INPUT_PULLUP);
      pinMode(buttonRed, INPUT_PULLUP);
      pinMode(buttonYellow, INPUT_PULLUP);
      pinMode(buttonSpecialYellow1, INPUT_PULLUP);
      pinMode(buttonSpecialYellow2, INPUT_PULLUP);
      pinMode(buttonSpecialBlue, INPUT_PULLUP);
    
      randomSeed(analogRead(0));
      newRound();
      Serial.begin(9600);  // Dans setup()
    }
    
    bool anyOtherAction(int correctButton1 = -1, int correctButton2 = -1) {
      return (digitalRead(buttonBlue) == LOW && buttonBlue != correctButton1 && buttonBlue != correctButton2) ||
             (digitalRead(buttonRed) == LOW && buttonRed != correctButton1 && buttonRed != correctButton2) ||
             (digitalRead(buttonYellow) == LOW && buttonYellow != correctButton1 && buttonYellow != correctButton2) ||
             (digitalRead(buttonSpecialYellow1) == LOW && buttonSpecialYellow1 != correctButton1 && buttonSpecialYellow1 != correctButton2) ||
             (digitalRead(buttonSpecialYellow2) == LOW && buttonSpecialYellow2 != correctButton1 && buttonSpecialYellow2 != correctButton2) ||
             (digitalRead(buttonSpecialBlue) == LOW && buttonSpecialBlue != correctButton1 && buttonSpecialBlue != correctButton2);
    }
    
    void loop() {
      if (timer <= 0) {
        // Afficher le score final
        lcd.clear();
        lcd.setCursor(0, 1);
        lcd.print("Final Score: ");
        lcd.print(score);
        delay(10000); // Attendre 10 secondes
    
        // Réinitialiser le jeu
        resetGame();
        return;
      }
    
      unsigned long currentMillis = millis();  // Obtenir le temps écoulé depuis le démarrage de l'Arduino
    
      // Vérifier si une seconde s'est écoulée
      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;  // Sauvegarder le temps actuel
        timer--;  // Décrémenter le timer
    
        // Effacer l'ancienne valeur du timer sur l'écran
        lcd.setCursor(6, 0);  // Se positionner à la position après "Time: "
        lcd.print("    ");     // Effacer l'affichage précédent (espaces pour effacer)
    
        // Afficher le timer actuel
        lcd.setCursor(6, 0);
        lcd.print(timer);    // Afficher le nombre de secondes restantes
      }
    
      prevPotValue = potValue;
      delay(100);
      potValue = analogRead(potPin);
      int potChange = abs(potValue - prevPotValue);  // Calculer l'écart de rotation du potentiomètre
      Serial.println(potChange);  // Dans loop()
    
      if (isDoubleYellow()) {
        if (digitalRead(buttonSpecialYellow1) == LOW && digitalRead(buttonSpecialYellow2) == LOW) {
          correctAnswer();
        } else if (anyOtherAction(buttonSpecialYellow1, buttonSpecialYellow2) || potChange > potThreshold) {
          wrongAnswer();
        }
      } else if (isDoubleBlue()) {
        if (digitalRead(buttonSpecialBlue) == LOW) {
          correctAnswer();
        } else if (anyOtherAction(buttonSpecialBlue) || potChange > potThreshold) {
          wrongAnswer();
        }
      } else if (isDoubleRed()) {
        // Si le potentiomètre a changé de façon significative (écart > 50), c'est une réponse correcte
        if (potChange > 100) {
          correctAnswer();
        } else if (anyOtherAction()) {
          wrongAnswer();
        }
      } else {
        checkRegularButtons();
        if (potChange > 100) {
          wrongAnswer();
        }
      }
    
       // Mettre à jour la valeur précédente du potentiomètre
    }
    
    void newRound() {
      turnOffAllLeds();
    
      int line1Leds[] = {ledBlue1, ledRed1, ledYellow1};
      currentLed1 = line1Leds[random(0, 3)];
    
      int line2Leds[] = {ledBlue2, ledRed2, ledYellow2};
      currentLed2 = line2Leds[random(0, 3)];
    
      digitalWrite(currentLed1, HIGH);
      digitalWrite(currentLed2, HIGH);
      lastResponseTime = millis();  // Réinitialiser le temps de réponse
    }
    
    void checkRegularButtons() {
      int correctButton = determineCorrectButton();
    
      if (digitalRead(correctButton) == LOW) {
        correctAnswer();
      } else if (anyOtherAction(correctButton)) {
        wrongAnswer();
      }
    }
    
    int determineCorrectButton() {
      if ((isRedLed(currentLed1) && isYellowLed(currentLed2)) ||       (isYellowLed(currentLed1) && isRedLed(currentLed2))) {
        return buttonBlue;
      }
      if ((isBlueLed(currentLed1) && isYellowLed(currentLed2)) ||       (isYellowLed(currentLed1) && isBlueLed(currentLed2))) {
        return buttonRed;
      }
      if ((isBlueLed(currentLed1) && isRedLed(currentLed2)) ||       (isRedLed(currentLed1) && isBlueLed(currentLed2))) {
        return buttonYellow;
      }
      if (isBlueLed(currentLed1) || isBlueLed(currentLed2)) {
        return buttonBlue;
      }
      if (isRedLed(currentLed1) || isRedLed(currentLed2)) {
        return buttonRed;
      }
      return buttonYellow;
    }
    
    bool isDoubleBlue() {
      return isBlueLed(currentLed1) && isBlueLed(currentLed2);
    }
    
    bool isDoubleRed() {
      return isRedLed(currentLed1) && isRedLed(currentLed2);
    }
    
    bool isDoubleYellow() {
      return isYellowLed(currentLed1) && isYellowLed(currentLed2);
    }
    
    bool isBlueLed(int led) {
      return (led == ledBlue1 || led == ledBlue2);
    }
    
    bool isRedLed(int led) {
      return (led == ledRed1 || led == ledRed2);
    }
    
    bool isYellowLed(int led) {
      return (led == ledYellow1 || led == ledYellow2);
    }
    
    void correctAnswer() {
      unsigned long reactionTime = millis() - lastResponseTime;  // Calcul du temps de réaction
      int points = 333 - reactionTime / 10;  // Réduction : 10 ms = -1 point, maximum 300 points
      points = max(0, points);  // Assurer que le score ne tombe pas en dessous de 0
    
      score += points;
    
      blinkAllLeds(5);  // Clignotement des LEDs pour signaler une réponse correcte
      newRound();       // Commencer un nouveau tour
      updateScore();    // Mettre à jour l'affichage du score
    }
    
    void wrongAnswer() {
      turnOnAllLeds();
      delay(2000);
      newRound();
    }
    
    void turnOffAllLeds() {
      digitalWrite(ledBlue1, LOW);
      digitalWrite(ledBlue2, LOW);
      digitalWrite(ledRed1, LOW);
      digitalWrite(ledRed2, LOW);
      digitalWrite(ledYellow1, LOW);
      digitalWrite(ledYellow2, LOW);
    }
    
    void turnOnAllLeds() {
      digitalWrite(ledBlue1, HIGH);
      digitalWrite(ledBlue2, HIGH);
      digitalWrite(ledRed1, HIGH);
      digitalWrite(ledRed2, HIGH);
      digitalWrite(ledYellow1, HIGH);
      digitalWrite(ledYellow2, HIGH);
    }
    
    void blinkAllLeds(int times) {
      for (int i = 0; i < times; i++) {
        turnOffAllLeds();
        delay(200);
        turnOnAllLeds();
        delay(200);
      }
    }
    
    void updateScore() {
      lcd.setCursor(7, 3);  // Se positionner sur la ligne 4 (index 3)
      lcd.print("    ");     // Effacer l'affichage précédent
      lcd.setCursor(7, 3);  // Repositionner le curseur
      lcd.print(score);      // Afficher le score actuel
    }
    
    void resetGame() {
      timer = 30;  // Réinitialiser le timer
      score = 0;    // Réinitialiser le score
      lcd.clear();  // Effacer l'écran
      lcd.setCursor(0, 0);
      lcd.print("Time: 30");  // Réafficher le timer initial
      lcd.setCursor(0, 3);
      lcd.print("Score: 0");  // Réinitialiser l'affichage du score
      newRound();   // Recommencer un nouveau tour
    }
  • 2
    Step 2

View all instructions

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates