You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
12 KiB
388 lines
12 KiB
#include <TFT_eSPI.h>
|
|
#include <LIS3DHTR.h>
|
|
#include <cstdlib> // Pour la fonction rand
|
|
#include <ctime> // Pour la fonction time
|
|
|
|
TFT_eSPI tft = TFT_eSPI();
|
|
LIS3DHTR<TwoWire> 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();
|
|
}
|