#include "FastLED.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "pitches.h" // Include library for musical notes
#define I2C_ADDRESS 0x27
#define DISPLAY_CHARS 16
#define DISPLAY_COLS 2
#define NUM_LEDS 32
#define DATA_PIN 7
#define SCORE_PIN 6
#define SCORE_LEDS 8
#define BUZZER_PIN 8
#define SCORE_EASY 5
#define SCORE_HARD 15
CRGB leds[NUM_LEDS], sleds[SCORE_LEDS]; // LED arrays
byte gameState = 0, Position = 0, level = 0, mode = 0;
int period = 1000;
unsigned long score = 0, time_now = 0;
const int targetscore = 35;
const byte ledSpeed[8] = {150, 125, 100, 85, 70, 55, 40, 25}; // LED speeds for each level
bool findRandom = false; // To find a random position for the target LEDs
bool ledJump = false; // To trigger the LED jump challenge
byte spot = 0; // Target LED position
uint8_t gHue = 0; // Hue for LED color animation
unsigned long jumpTime = 0; // Time for next LED jump
LiquidCrystal_I2C lcd(I2C_ADDRESS, DISPLAY_CHARS, DISPLAY_COLS); // LCD object
// Melody and note durations for the win sound
const int melody[] = {NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4};
const int noteDurations[] = {4, 8, 8, 4, 4, 4, 4, 4};
void setup() {
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS); // Initialize LED strip
FastLED.addLeds<WS2812B, SCORE_PIN, GRB>(sleds, SCORE_LEDS); // Initialize score LEDs
pinMode(4, INPUT_PULLUP); // Button input
pinMode(BUZZER_PIN, OUTPUT); // Buzzer output
Serial.begin(9600); // Serial communication for debugging
lcd.init(); // Initialize LCD
lcd.backlight(); // Turn on LCD backlight
}
void loop() {
if (gameState == 0) { // Idle state
ModeSelection(); // Mode selection screen
} else if (gameState == 1) { // Idle state after mode selection
IdleWipe(); // Show LED animation
lcd.setCursor(0, 0); lcd.print("CyClone"); // Display game name
lcd.setCursor(0, 1); lcd.print("Free Play"); // Display mode
if (digitalRead(4) == LOW) { // Start game on button press
Position = 0; findRandom = true; delay(500);
startSound(); // Play start sound
lcd.clear(); lcd.setCursor(3, 0); lcd.print("Game START"); // Display start message
delay(1000); lcd.clear(); clearLEDS(); gameState = 2; score = 0; // Initialize game
jumpTime = millis() + random(3000, 7000); // Set random time for first LED jump
}
FastLED.show();
} else if (gameState >= 2 && gameState <= 9) { // Game levels
period = ledSpeed[gameState - 2]; // Set LED speed based on level
if (millis() > time_now + period) { // Move LEDs periodically
time_now = millis();
if (findRandom) { spot = random(NUM_LEDS - 4) + 2; findRandom = false; } // Set target LEDs
if (millis() > jumpTime) { // Check if it's time for the LED to jump
spot = random(NUM_LEDS - 4) + 2; // Jump to a new random position
jumpTime = millis() + random(3000, 7000); // Set time for the next jump
}
leds[spot - 1].setRGB(0, 150, 0); leds[spot].setRGB(0, 255, 0); leds[spot + 1].setRGB(0, 150, 0); // Target LEDs
sleds[gameState - 2].setRGB(0, 255, 190); PlayGame(spot - 1, spot + 1); // Play game
}
if (digitalRead(4) == LOW) { // Check button press for player move
delay(300);
if (Position > spot - 1 && Position < spot + 2) { // Check if player hits target
level = gameState; gameState = 98; // Proceed to next level
score += (mode == 0) ? SCORE_EASY : SCORE_HARD; // Update score based on mode
} else { gameState = 99; } // Player missed target
}
} else if (gameState == 98) winner(); // Player wins level
else if (gameState == 99) loser(); // Player loses
}
void ModeSelection() {
lcd.clear();
lcd.setCursor(0, 0); lcd.print("Select Mode:");
bool selecting = true;
while (selecting) {
lcd.setCursor(0, 1);
if (mode == 0) lcd.print("> Beginner ");
else if (mode == 1) lcd.print("> Advanced ");
else lcd.print("> Challenge ");
if (digitalRead(4) == LOW) { // Confirm mode selection
delay(300);
selecting = false;
} else { // Cycle through modes on button press
delay(300);
if (digitalRead(4) == LOW) { // Check if button is pressed again
delay(300); // Debounce
mode = (mode + 1) % 3; // Cycle through modes
}
}
}
gameState = 1;
lcd.clear();
}
void PlayGame(byte bound1, byte bound2) {
lcd.setCursor(0, 0); lcd.print("CyClone");
lcd.setCursor(0, 1); lcd.print("Level : " + String(gameState - 1)); // Display level
leds[Position].setRGB(0, 200, 150); // Move player LED
tone(BUZZER_PIN, 1000, 50); // Play move sound
if (Position < bound1 + 1 || Position > bound2 + 1) leds[Position - 1].setRGB(0, 0, 0); // Clear previous LED
FastLED.show(); Position++;
if (Position >= NUM_LEDS) { leds[Position - 1].setRGB(0, 0, 0); Position = 0; } // Loop position
}
void winner() {
fill_solid(leds, NUM_LEDS, CRGB::Green); FastLED.show(); // Set all LEDs to green
for (int thisNote = 0; thisNote < 8; thisNote++) { // Play win melody
int noteDuration = 1000 / noteDurations[thisNote];
tone(BUZZER_PIN, melody[thisNote], noteDuration);
delay(noteDuration * 1.30); noTone(BUZZER_PIN);
}
lcd.clear(); lcd.setCursor(0, 0); lcd.print("You Win!"); // Display win message
lcd.setCursor(0, 1); lcd.print("Score : " + String(score));
delay(2000); lcd.clear(); clearLEDS(); delay(100); findRandom = true; Position = 0;
gameState = level + 1; if (gameState > 9) { gameState = 0; winAll(); } // Proceed to next level or end game
}
void loser() {
fill_solid(leds, NUM_LEDS, CRGB::Red); FastLED.show(); // Set all LEDs to red
loseSound(); // Play lose sound
lcd.clear(); lcd.setCursor(0, 0); lcd.print("Try Again!"); // Display lose message
lcd.setCursor(0, 1); lcd.print("Score : " + String(score));
delay(2000); lcd.clear(); clearLEDS(); gameState = 0; // Reset game
}
void clearLEDS() {
fill_solid(leds, NUM_LEDS, CRGB::Black); FastLED.show(); // Clear all LEDs
}
void winAll() {
lcd.clear(); lcd.setCursor(0, 0); lcd.print(score >= targetscore ? "REWARD GET!" : "Nice Score!");
lcd.setCursor(0, 1); lcd.print("Score : " + String(score)); delay(5000); lcd.clear(); // Display final score
}
void IdleWipe() {
EVERY_N_MILLISECONDS(10) { gHue++; }
fill_rainbow(leds, NUM_LEDS, gHue, 10);
fadeToBlackBy(leds, NUM_LEDS, 20); fadeToBlackBy(sleds, SCORE_LEDS, 20);
int spos = beatsin8(13, 0, SCORE_LEDS - 1); sleds[spos] += CHSV(gHue, 255, 192); delay(10); // Idle LED animation
}
void startSound() {
tone(BUZZER_PIN, NOTE_C5, 200); delay(250); tone(BUZZER_PIN, NOTE_E5, 200); delay(250);
tone(BUZZER_PIN, NOTE_G5, 200); delay(250); noTone(BUZZER_PIN); // Play start sound
}
void loseSound() {
tone(BUZZER_PIN, NOTE_C4, 400); delay(450); tone(BUZZER_PIN, NOTE_A3, 400); delay(450);
tone(BUZZER_PIN, NOTE_F3, 400); delay(450); noTone(BUZZER_PIN); // Play lose sound
}