// Jeu Reflex 2J — version ESP32 + OLED SSD1306 (SDA=21, SCL=22, addr=0x3C)
// Boutons en INPUT_PULLUP (appuyé = LOW). LEDs pilotées par GPIO (ou via transistor si LED = 5V).
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "esp_system.h" // pour esp_random()
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// --- Brochage ---
#define BTN_GO_PIN 23
#define LED_GO_PIN 22
#define BTN_J1_PIN 15
#define LED_J1_PIN 19
#define BTN_J2_PIN 18
#define LED_J2_PIN 5
#define BUZZER_PIN 4 // <-- ajout du buzzer sur D4
#define LED_BUILTIN 2 // ⚠️ la plupart du temps c’est GPIO 2
// --- Paramètres ---
const int TOTAL_ROUNDS = 5;
const unsigned long LONG_PRESS = 2000; // 2s pour reset
const unsigned long DEBOUNCE_DELAY = 50; // ms
// --- Variables globales ---
int roundCount = 0;
int score1 = 0, score2 = 0;
unsigned long startTime;
unsigned long time1, time2;
bool waitingForPress = false;
bool gameRunning = true;
void setup() {
// I2C pour OLED sur ESP32
Wire.begin(8, 9); // SDA = 21, SCL = 22
pinMode(BTN_GO_PIN, INPUT_PULLUP);
pinMode(BTN_J1_PIN, INPUT_PULLUP);
pinMode(BTN_J2_PIN, INPUT_PULLUP);
pinMode(LED_GO_PIN, OUTPUT);
pinMode(LED_J1_PIN, OUTPUT);
pinMode(LED_J2_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT); // <-- configuration du buzzer
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_GO_PIN, LOW);
digitalWrite(LED_J1_PIN, LOW);
digitalWrite(LED_J2_PIN, LOW);
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW); // ou HIGH selon le sens de la LED
//WiFi.mode(WIFI_OFF); // désactive complètement le Wi-Fi
//btStop(); // si le Bluetooth est activé par défaut, désactive aussi
// le reste de ton setup
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 allocation failed");
for(;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
// seed aléatoire raisonnable
randomSeed(esp_random());
showIntro();
}
// --- petite fonction pour bipper ---
void beep(int duration = 200) {
digitalWrite(BUZZER_PIN, HIGH);
delay(duration);
digitalWrite(BUZZER_PIN, LOW);
}
void showIntro() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(8, 20);
display.println("Reflex'Bocal");
display.setTextSize(1);
display.setCursor(6, 44);
display.println("Reflex 2J");
display.display();
delay(1200);
}
void loop() {
if (!gameRunning) {
// jeu terminé : appui long sur GO pour reset
if (longPressDetected()) {
resetGame();
delay(400);
}
return;
}
showStatus();
int pressType = detectButtonPress();
if (pressType == 1) { // Appui court = manche suivante
if (roundCount < TOTAL_ROUNDS) {
playRound();
} else {
showWinner();
gameRunning = false;
}
} else if (pressType == 2) { // Appui long = reset
resetGame();
}
}
// Jouer une manche
void playRound() {
roundCount++;
time1 = 0;
time2 = 0;
// --- Préparation ---
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.print("Manche ");
display.println(roundCount);
display.println("Preparez-vous...");
display.display();
// Délai aléatoire entre 1 et 4 secondes
unsigned long waitStart = millis();
unsigned long waitDelay = random(1000, 4000);
bool falseStart = false;
int fautif = 0;
// --- Surveillance pendant l’attente ---
while (millis() - waitStart < waitDelay) {
if (digitalRead(BTN_J1_PIN) == LOW) {
falseStart = true;
fautif = 1;
//beep(800); // bip plus long si faute
break;
}
if (digitalRead(BTN_J2_PIN) == LOW) {
falseStart = true;
fautif = 2;
//beep(800); // bip plus long si faute
break;
}
delay(5);
}
if (falseStart) {
// --- Gestion de la faute ---
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.print("FAUTE ! Joueur ");
display.println(fautif);
display.print("a appuye trop tot !");
display.display();
// L’autre joueur gagne le point
if (fautif == 1) {
score2++;
blinkLED(LED_J2_PIN, 3);
} else {
score1++;
blinkLED(LED_J1_PIN, 3);
}
delay(1500);
return; // Fin de la manche
}
// --- Signal GO ---
digitalWrite(LED_GO_PIN, HIGH);
startTime = millis();
waitingForPress = true;
// Allume tout l’écran (fond blanc)
display.clearDisplay();
display.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
// Écrit "GO !" en noir au centre
display.setTextSize(3);
display.setTextColor(SSD1306_BLACK); // texte noir sur fond blanc
int16_t x = 30;
int16_t y = 20;
display.setCursor(x, y);
display.println("GO!");
display.display();
display.setTextColor(SSD1306_WHITE);
// --- Attente des réactions ---
while (waitingForPress) {
if (digitalRead(BTN_J1_PIN) == LOW && time1 == 0) {
//beep(400); // bip à chaque appui joueur
time1 = millis() - startTime;
}
if (digitalRead(BTN_J2_PIN) == LOW && time2 == 0) {
//beep(400); // bip à chaque appui joueur
time2 = millis() - startTime;
}
if (time1 > 0 && time2 > 0) waitingForPress = false;
if (millis() - startTime > 10000) waitingForPress = false;
delay(5);
}
digitalWrite(LED_GO_PIN, LOW);
showRoundResult();
delay(1500);
}
void showRoundResult() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.print("J1: ");
display.print(time1);
display.println(" ms");
display.print("J2: ");
display.print(time2);
display.println(" ms");
display.println();
if (time1 > 0 && (time2 == 0 || time1 < time2)) {
display.println(">> Joueur 1 gagne !");
score1++;
blinkLED(LED_J1_PIN, 4);
} else if (time2 > 0 && (time1 == 0 || time2 < time1)) {
display.println(">> Joueur 2 gagne !");
score2++;
blinkLED(LED_J2_PIN, 4);
} else {
display.println("Egalite !");
digitalWrite(LED_J1_PIN, HIGH);
digitalWrite(LED_J2_PIN, HIGH);
delay(400);
digitalWrite(LED_J1_PIN, LOW);
digitalWrite(LED_J2_PIN, LOW);
}
display.println();
display.print("Score: ");
display.print(score1);
display.print(" - ");
display.println(score2);
display.display();
}
void showStatus() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.print("Manche: ");
display.print(roundCount);
display.print("/");
display.println(TOTAL_ROUNDS);
display.print("Score J1-J2: ");
display.print(score1);
display.print(" - ");
display.println(score2);
display.println();
display.println("Appui court:");
display.println(" Manche suivante");
display.println("Appui long:");
display.println(" Reset");
display.display();
}
void showWinner() {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
if (score1 > score2) display.println("Joueur 1");
else if (score2 > score1) display.println("Joueur 2");
else display.println("Egalite !");
display.setTextSize(1);
display.setCursor(0,34);
display.println("gagne la partie !");
display.display();
}
void resetGame() {
roundCount = 0;
score1 = 0;
score2 = 0;
gameRunning = true;
display.clearDisplay();
display.setCursor(20, 25);
display.setTextSize(1);
display.println("Reinitialise...");
display.display();
delay(1000);
}
void blinkLED(int pin, int times) {
for (int i = 0; i < times; i++) {
digitalWrite(pin, HIGH);
delay(150);
digitalWrite(pin, LOW);
delay(150);
}
}
int detectButtonPress() {
// 0 = rien, 1 = court, 2 = long
if (digitalRead(BTN_GO_PIN) == LOW) {
unsigned long pressStart = millis();
while (digitalRead(BTN_GO_PIN) == LOW) {
if (millis() - pressStart > LONG_PRESS) return 2;
delay(10);
}
delay(DEBOUNCE_DELAY);
return 1;
}
return 0;
}
bool longPressDetected() {
if (digitalRead(BTN_GO_PIN) == LOW) {
unsigned long start = millis();
while (digitalRead(BTN_GO_PIN) == LOW) {
if (millis() - start > LONG_PRESS) return true;
delay(10);
}
}
return false;
}