Hey everyone,
Im new to the arduino community and new to coding.
For my first "big" project i wanted to create a snake game on a 8*8 led square.
Ive been working on it for three days but cannot figure out how to make certain things work, i would love a little help and explanations.
Before Sharing my code this is my setup for this project :
Board : Arduino Nano
Elegoo Joystick (GND to Arduino GND,5V to Arduino 5V,VRx to A0,VRy to A1,SW to D8)
8*8 WS2812b led square with V+ to external 5V psu, 1N to D2 with 330 ohm resistor, V- to external psu and Arduino GND.
My Setup is working since i have tested with some easy animations and serial monitor, everything is working fine.
So my problem is : I want my snake game to display a Score in two digits, number of apples eaten, drawn on the leds like 01,02,03, etc when a game is over, And then be able to press the joystick button (SW) to restart a game, ever and ever until power off.
My snake game is perfectly working, my snake eats apples, grow, becomes faster, can collide with edges and himself. The problem happens when gameover, the score is not displayed properly i can only get two leds to light up, and impossible to restart using my sw button.
Im at my limits since i dont know very much, i tried asking chatgpt but nothing was successful and everything was just messing with my original code.
So if any of you can help me fix this i would gladly appreciate it, and teach me where i was making mistake, thank you and here is my code (i can only use FastLed since its the only library that works with those leds) (comments are in french for myself) :
#include <FastLED.h>
#define DATA_PIN 2 // Broche de données du carré de LED
#define NUM_LEDS 64 // Nombre de LEDs (8x8)
#define JOYSTICK_X A0 // Broche analogique pour VRx
#define JOYSTICK_Y A1 // Broche analogique pour VRy
#define JOYSTICK_SW 8 // Broche pour le bouton du joystick
#define LED_INDEX 12 // Indice de la LED de départ du Snake
CRGB leds[NUM_LEDS];
int snakeLength = 3; // Longueur initiale du Snake
int snakeX[64]; // Coordonnées X du Snake
int snakeY[64]; // Coordonnées Y du Snake
int appleX, appleY; // Coordonnées de la pomme
int direction = 1; // Direction du Snake (0: haut, 1: droite, 2: bas, 3: gauche)
int speed = 350; // Vitesse de déplacement du Snake (plus la valeur est basse, plus il est rapide)
unsigned long lastMoveTime; // Dernier moment oĂč le Snake a bougĂ©
bool gameOverFlag = false; // Drapeau pour indiquer la fin du jeu
int applesEaten = 0; // Nombre de pommes mangées
bool restartGame = false; // Drapeau pour indiquer le redémarrage du jeu
void setup() {
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
FastLED.show();
randomSeed(analogRead(0)); // Initialisation du générateur de nombres aléatoires
// Appel de la fonction resetGame pour initialiser le jeu
resetGame();
lastMoveTime = millis();
pinMode(JOYSTICK_SW, INPUT_PULLUP); // Configuration du bouton du joystick en mode INPUT_PULLUP
}
void loop() {
if (!gameOverFlag) {
unsigned long currentTime = millis();
if (currentTime - lastMoveTime >= speed) {
moveSnake();
lastMoveTime = currentTime;
}
checkCollision();
// Gestion du joystick
int xValue = analogRead(JOYSTICK_X);
int yValue = analogRead(JOYSTICK_Y);
if (xValue < 100) { // Joystick vers la gauche
changeDirection(3); // Changer la direction Ă gauche
} else if (xValue > 900) { // Joystick vers la droite
changeDirection(1); // Changer la direction Ă droite
} else if (yValue < 100) { // Joystick vers le haut
changeDirection(0); // Changer la direction vers le haut
} else if (yValue > 900) { // Joystick vers le bas
changeDirection(2); // Changer la direction vers le bas
}
// Si restartGame est vrai, réinitialise le jeu
if (restartGame) {
resetGame();
}
} else {
// Afficher le nombre de pommes mangées en rouge
displayScore();
// Attendre que le bouton du joystick soit enfoncé pour redémarrer le jeu
if (digitalRead(JOYSTICK_SW) == HIGH) {
restartGame = true; // Mettre restartGame à vrai pour redémarrer le jeu
}
}
FastLED.show();
}
void moveSnake() {
// DĂ©placer le Snake en ajoutant une nouvelle tĂȘte dans la direction actuelle
int newHeadX = snakeX[0];
int newHeadY = snakeY[0];
switch (direction) {
case 0: // Haut
newHeadY--;
break;
case 1: // Droite
newHeadX++;
break;
case 2: // Bas
newHeadY++;
break;
case 3: // Gauche
newHeadX--;
break;
}
// DĂ©placer le corps du Snake
for (int i = snakeLength - 1; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
// Mettre Ă jour la position de la tĂȘte du Snake
snakeX[0] = newHeadX;
snakeY[0] = newHeadY;
// Vérifier si le Snake a mangé une pomme
if (snakeX[0] == appleX && snakeY[0] == appleY) {
snakeLength++;
spawnApple();
// Accélérer légÚrement le Snake
if (speed > 20) {
speed -= 5;
}
}
// Afficher le Snake et la pomme
clearBoard();
drawSnake();
drawApple();
}
void checkCollision() {
// Vérifier si le Snake a heurté les bords
if (snakeX[0] < 0 || snakeX[0] >= 8 || snakeY[0] < 0 || snakeY[0] >= 8) {
gameOver();
}
// Vérifier si le Snake a mangé son propre corps
for (int i = 1; i < snakeLength; i++) {
if (snakeX[i] == snakeX[0] && snakeY[i] == snakeY[0]) {
gameOver();
}
}
}
void spawnApple() {
appleX = random(8);
appleY = random(8);
}
void drawSnake() {
for (int i = 0; i < snakeLength; i++) {
leds[snakeX[i] + snakeY[i] * 8] = CRGB(0, 255, 0); // Couleur du Snake (vert)
}
}
void drawApple() {
leds[appleX + appleY * 8] = CRGB(255, 0, 0); // Couleur de la pomme (rouge)
}
void clearBoard() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB(0, 0, 0); // Ăteindre toutes les LEDs
}
}
void displayScore() {
// Afficher le nombre de pommes mangées en rouge
clearBoard();
int tens = applesEaten / 10; // Dizaines
int units = applesEaten % 10; // Unités
int scoreIndex = 6; // Indice de la LED Ă partir duquel afficher le score
// Afficher les dizaines
if (tens > 0) {
leds[scoreIndex] = CRGB(255, 0, 0);
scoreIndex--;
leds[scoreIndex] = CRGB(255, 0, 0);
scoreIndex--;
}
// Afficher les unités
leds[scoreIndex] = CRGB(255, 0, 0);
scoreIndex--;
// Mettre Ă jour le score
FastLED.show();
}
void gameOver() {
gameOverFlag = true;
clearBoard();
displayScore();
FastLED.show();
restartGame = false; // Ne pas redémarrer automatiquement
}
void resetGame() {
snakeLength = 3;
direction = 1;
speed = 150;
gameOverFlag = false;
applesEaten = 0;
// Réinitialiser la position de départ du Snake
snakeX[0] = 3;
snakeY[0] = 3;
// RĂ©initialiser la position de la pomme
spawnApple();
// Effacer l'affichage du score
clearBoard();
// RĂ©initialiser la variable restartGame Ă faux
restartGame = false;
}
void changeDirection(int newDirection) {
if ((newDirection == 0 && direction != 2) || // Nouvelle direction : haut, direction actuelle : bas
(newDirection == 1 && direction != 3) || // Nouvelle direction : droite, direction actuelle : gauche
(newDirection == 2 && direction != 0) || // Nouvelle direction : bas, direction actuelle : haut
(newDirection == 3 && direction != 1)) { // Nouvelle direction : gauche, direction actuelle : droite
direction = newDirection;
}
}