#include #include #include // Pour la fonction rand #include // Pour la fonction time TFT_eSPI tft = TFT_eSPI(); LIS3DHTR lis; //Constantes : //couleurs : #define TFT_BLACK 0x0000 /* 0, 0, 0 */ #define TFT_NAVY 0x000F /* 0, 0, 128 */ #define TFT_DARKGREEN 0x03E0 /* 0, 128, 0 */ #define TFT_DARKCYAN 0x03EF /* 0, 128, 128 */ #define TFT_MAROON 0x7800 /* 128, 0, 0 */ #define TFT_PURPLE 0x780F /* 128, 0, 128 */ #define TFT_OLIVE 0x7BE0 /* 128, 128, 0 */ #define TFT_LIGHTGREY 0xC618 /* 192, 192, 192 */ #define TFT_DARKGREY 0x7BEF /* 128, 128, 128 */ #define TFT_BLUE 0x001F /* 0, 0, 255 */ #define TFT_GREEN 0x07E0 /* 0, 255, 0 */ #define TFT_CYAN 0x07FF /* 0, 255, 255 */ #define TFT_RED 0xF800 /* 255, 0, 0 */ #define TFT_MAGENTA 0xF81F /* 255, 0, 255 */ #define TFT_YELLOW 0xFFE0 /* 255, 255, 0 */ #define TFT_WHITE 0xFFFF /* 255, 255, 255 */ #define TFT_ORANGE 0xFDA0 /* 255, 180, 0 */ #define TFT_GREENYELLOW 0xB7E0 /* 180, 255, 0 */ #define PIECE_RADIUS 5 #define PIECE_COUNT 5 #define SPEEDGAME 3 // Paramètres du jeu : bool isGameRunning = false; int rep = 1; unsigned long lastButtonPressTime = 0; unsigned long lastTimeDecrement = 0; // Stocke le moment où la dernière seconde a été décrémentée unsigned long timeInterval = 1000; // Interval de temps en millisecondes (1000 ms = 1 seconde) int score = 0; // Initialisation du score int timeLeft = 30; // Initialisation du timer String oldLevel = ""; // Niveau précédent int oldScore = -1; // Score précédent int oldTimeLeft = -1; // Temps précédent String level = "Novice"; // Initialisation du niveau (changeable après) int ballRadius = 7; // rayon de la boule rouge int ballX = 160; // coordonné x du centre de la boule int ballY = 120; // coordonné y du centre de la boule int oldBallX = ballX; // stocker les anciennes coordonnées de la balle int oldBallY = ballY; // stocker les anciennes coordonnées de la balle int currentLevelIndex = 0; String levels[3] = {"Novice", "Confirmé", "Expert"}; // Assurez-vous que les niveaux sont dans le bon ordre struct Piece { int x; int y; bool isCollected; bool isBlack; }; // Niveau Novice Piece novicePieces[5] = { {50, 60, false, false}, {260, 100, false, false}, {220, 180, false, false}, {145, 165, false, false}, {60, 190, false, false}, }; // Niveau confirmé Piece confirmedPieces[5] = { {270, 60, false, false}, {255, 140, false, false}, {70, 70, false, false}, {40, 220, false, false}, {160, 200, false, false}, }; // Niveau Expert Piece expertPieces[10] = { {50, 60, false, false}, {320 - 70, 240 - 100, false, false}, {90, 240 - 140, false, false}, {320 - 110, 100, false, false}, {19, 220, false, false}, // Pièces noires {80, 80, false, true}, {320 - 80, 240 - 80, false, true}, {80, 240 - 80, false, true}, {320 - 80, 80, false, true}, {160, 60, false, true}, }; Piece* currentPieces = novicePieces; int currentPieceCount = 5; // variable pour stocker les données de l'accèléromètre float accX, accY; void addsound(int number){ // GESTION DU SON switch (number) { pinMode(WIO_BUZZER, OUTPUT); case 0: // SON DE CHOIX DE NIVEAU analogWrite(WIO_BUZZER,100); delay(100); analogWrite(WIO_BUZZER,0); delay(100); analogWrite(WIO_BUZZER,100); delay(100); analogWrite(WIO_BUZZER,0); delay(100); analogWrite(WIO_BUZZER,100); delay(100); analogWrite(WIO_BUZZER,0); break; case 1: // SON LORS DE PIECE JAUNE for(int i=0; i< 1000000 ; i+=1014 *2){ digitalWrite(WIO_BUZZER, HIGH); delayMicroseconds(900); digitalWrite(WIO_BUZZER, LOW); delayMicroseconds(900); } break; case 2: // SON LORS DE PIECE NOIRE for(int i=0; i< 1000000 ; i+=1014 *2){ digitalWrite(WIO_BUZZER, HIGH); delayMicroseconds(1100); digitalWrite(WIO_BUZZER, LOW); delayMicroseconds(1100); } break; case 3: // SON LORS DE FIN DE NIVEAU analogWrite(WIO_BUZZER,128); analogWrite(WIO_BUZZER,0); break; case 4: for(int i=0; i< 1000000 ; i+=500 *2){ digitalWrite(WIO_BUZZER, HIGH); delayMicroseconds(500); digitalWrite(WIO_BUZZER, LOW); delayMicroseconds(1100); } break; } } void checkButtonAState(){ // GESTION AJOUT DE TEMPS int buttonState=digitalRead(WIO_KEY_A); if (buttonState==LOW && rep == 1){ timeLeft=timeLeft+10; rep=2; } } float distance(int x1, int y1, int x2, int y2){ return sqrt(sq(x2 - x1) + sq(y2 - y1)); } void setupButtonAndScreen() { pinMode(WIO_KEY_A, INPUT_PULLUP); pinMode(WIO_KEY_B, INPUT_PULLUP); pinMode(WIO_KEY_C, INPUT_PULLUP); tft.begin(); tft.setRotation(3); // dessine la bannière bleu tft.fillRoundRect(0, 0, 320, 40, 0, TFT_BLUE); tft.fillRoundRect(0, 40, 320, 200, 0, TFT_DARKGREY); //set la couleur du text tft.setTextColor(TFT_WHITE, TFT_BLUE); tft.setTextSize(2); // Affichage du niveau, score et timer tft.drawString(level, 10, 10); tft.drawString(String(score)+" pts", 160, 10); tft.drawString(String(timeLeft), 290, 10); //dessine la boule rouge : tft.fillCircle(ballX, ballY, ballRadius, TFT_RED); } void setupAccelerometer() { lis.begin(Wire1); if (!lis) { while (1); } lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); lis.setFullScaleRange(LIS3DHTR_RANGE_2G); } void checkButtonState() { int buttonState = digitalRead(WIO_KEY_B); if(buttonState == LOW && isGameRunning == false){ lastTimeDecrement = millis(); addsound(0); resetGame(); } } void drawPieces() { for (int i = 0; i < currentPieceCount; i++) { if (!currentPieces[i].isCollected) { tft.fillCircle(currentPieces[i].x, currentPieces[i].y, PIECE_RADIUS, currentPieces[i].isBlack ? TFT_BLACK : TFT_YELLOW); } } } void updateBallPosition() { delay(10); // Lire les données de l'accéléromètre accX = -lis.getAccelerationY(); accY = lis.getAccelerationX(); // Nettoyer l'ancienne position de la balle tft.fillCircle(oldBallX, oldBallY, ballRadius, TFT_DARKGREY); // Déplacer la balle en fonction des données de l'accéléromètre ballX += accX * SPEEDGAME; ballY += accY * SPEEDGAME; // Si la balle dépasse les limites de l'écran, arrêter le jeu if (ballX < 0 + ballRadius || ballX > 320 - ballRadius || ballY < 40 + ballRadius || ballY > 240 - ballRadius) { isGameRunning = false; return; } // Dessiner la nouvelle position de la balle tft.fillCircle(ballX, ballY, ballRadius, TFT_RED); // Mettre à jour les anciennes coordonnées de la balle oldBallX = ballX; oldBallY = ballY; } void checkTime() { // Gestion du chronomètre if (millis() - lastTimeDecrement >= timeInterval) { // Une seconde s'est écoulée, décrémentez le timer et mettez à jour le moment du dernier décrément timeLeft--; lastTimeDecrement = millis(); } // Si le temps est écoulé, arrêtez le jeu if (timeLeft <= 0) { addsound(3); isGameRunning = false; } } void updateBanner() { // Vérifier si les valeurs ont changé if (level != oldLevel || score != oldScore || timeLeft != oldTimeLeft) { // Actualiser le bandeau tft.fillRoundRect(0, 0, 320, 40, 0, TFT_BLUE); tft.drawString(level, 10, 10); tft.drawString(String(score) + " pts", 160, 10); tft.drawString(String(timeLeft), 290, 10); // Mettre à jour les valeurs précédentes oldLevel = level; oldScore = score; oldTimeLeft = timeLeft; } } void displayPieces() { uint16_t oldTextColor = TFT_WHITE; uint8_t oldTextSize = 2; // Effacer toutes les pièces précédentes tft.fillRoundRect(0, 40, 320, 200, 0, TFT_DARKGREY); // Afficher les nouvelles pièces for (int i = 0; i < currentPieceCount; i++) { if (!currentPieces[i].isCollected) { // Choisissez la couleur de la pièce int pieceColor = currentPieces[i].isBlack ? TFT_BLACK : TFT_YELLOW; tft.fillCircle(currentPieces[i].x, currentPieces[i].y, PIECE_RADIUS, pieceColor); // Si la pièce est jaune, ajoutez le symbole '$' if (!currentPieces[i].isBlack) { tft.setTextColor(TFT_BLACK, pieceColor); tft.setTextSize(1); tft.setCursor(currentPieces[i].x - 3, currentPieces[i].y - 3); tft.print("$"); } } } tft.setTextColor(oldTextColor); tft.setTextSize(oldTextSize); } void checkColision() { for (int i = 0; i < currentPieceCount; i++) { if (!currentPieces[i].isCollected && distance(ballX, ballY, currentPieces[i].x, currentPieces[i].y) < ballRadius + PIECE_RADIUS) { currentPieces[i].isCollected = true; tft.fillCircle(currentPieces[i].x, currentPieces[i].y, 5, TFT_DARKGREY); if (currentPieces[i].isBlack) { timeLeft -= 10; // Enlève 5 secondes addsound(2); } else { addsound(1); srand(time(0)); int points_ajoutes = rand() % 16 + 10; // tire un entier au sort aléatoirement entre 10 et 25 score += points_ajoutes; //ajoute le score de la pièce au score de la partie } } } } void changeLevel() { if (isGameRunning) { // Si le jeu est en cours, ne faites rien et sortez de la fonction return; } int buttonState = digitalRead(WIO_KEY_C); if(buttonState == LOW && millis() - lastButtonPressTime > 500){ lastButtonPressTime = millis(); // Mise à jour du temps du dernier appui sur le bouton currentLevelIndex++; if(currentLevelIndex >= 3) currentLevelIndex = 0; //retourne à 0 si le niveau dépasse le maximum level = levels[currentLevelIndex]; if(level == "Novice") { currentPieces = novicePieces; currentPieceCount = sizeof(novicePieces) / sizeof(novicePieces[0]); } else if(level == "Confirmé") { currentPieces = confirmedPieces; currentPieceCount = sizeof(confirmedPieces) / sizeof(confirmedPieces[0]); } else if(level == "Expert") { currentPieces = expertPieces; currentPieceCount = sizeof(expertPieces) / sizeof(expertPieces[0]); } // Reset le score score = 0; // Réinitialise l'état des pièces for (int i = 0; i < currentPieceCount; i++) { currentPieces[i].isCollected = false; } displayPieces(); // Afficher les pièces après avoir changé de niveau updateBanner(); // Mettre à jour le bandeau après avoir changé le niveau } } void resetGame() { isGameRunning = true; // Ajoutez cette ligne pour redémarrer le jeu timeLeft = 30; level = "Novice"; ballX = 160; ballY = 120; oldBallX = ballX; oldBallY = ballY; currentLevelIndex = 0; score = 0; currentPieces = novicePieces; currentPieceCount = sizeof(novicePieces) / sizeof(novicePieces[0]); for (int i = 0; i < currentPieceCount; i++) { currentPieces[i].isCollected = false; } displayPieces(); updateBanner(); } void setup() { Serial.begin(115200); setupButtonAndScreen(); setupAccelerometer(); pinMode(WIO_KEY_C, INPUT_PULLUP); displayPieces(); // Afficher les pièces dès le démarrage } void loop() { checkButtonState(); changeLevel(); if(isGameRunning){ updateBallPosition(); checkTime(); checkButtonAState(); } else tft.fillCircle(ballX, ballY, ballRadius, TFT_RED); updateBanner(); // Mettre à jour le bandeau dans chaque boucle, que le jeu soit en cours ou non checkColision(); }