Mirko Pavleski
Published © GPL3+

DIY simple HUNTER LED game with Arduino

This is a custom version of the Hunter game with 10 LED and LCD display to show the score, followed by various sound effects.

BeginnerFull instructions provided3 hours770
DIY simple HUNTER LED game with Arduino

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
I2C 16x2 Arduino LCD Display Module
DFRobot I2C 16x2 Arduino LCD Display Module
×1
LED (generic)
LED (generic)
×10
Buzzer
Buzzer
×1
Pushbutton Switch, Momentary
Pushbutton Switch, Momentary
×2
Resistor 10k ohm
Resistor 10k ohm
×2
Through Hole Resistor, 470 ohm
Through Hole Resistor, 470 ohm
×10

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Schematic 10 resistors

..

Code

Code

C/C++
..
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Initialize the LCD, set the address to 0x27 or 0x3F depending on your module
LiquidCrystal_I2C lcd(0x27, 16, 2);  // 16 columns, 2 rows

// Pin setup
int ledPins[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13};  // Pins for the 8 LEDs
int buttonPin = 2;  // Pin for the button
int buzzerPin = 3;  // Pin for the piezo buzzer
int middleLED = 5;   // The middle LED position (adjust if needed)
int direction = 1;   // Initial direction (1 = forward, -1 = backward)
int currentLED = 0;  // Start at the first LED
int level = 1;       // Start at level 1
int delayTime = 300; // Initial delay time for LED movement (in ms)
int score = 0;       // Player score
int levelTime = 10;  // Time allowed for each level (in seconds)
unsigned long startTime;  // Time when the level starts
unsigned long lastMoveTime = 0;  // Time when the LEDs last moved
unsigned long lastToneTime = 0;  // Time to control the duration of the tone
unsigned long buttonDebounceTime = 0; // For button debouncing
unsigned long debounceDelay = 50;     // Debounce delay in milliseconds

int lastRemainingTime = -1; // To track the last displayed time
int lastLevel = -1;         // To track the last displayed level
int lastScore = -1;         // To track the last displayed score

bool buttonPressed = false;
bool tonePlaying = false;  // Flag to indicate whether the tone is currently playing
bool gameEnded = false;    // Flag to indicate the end of the game

// Function to play a tone non-blocking
void startTone(int frequency) {
  tone(buzzerPin, frequency);  // Start playing the tone
  tonePlaying = true;          // Set tone playing flag
  lastToneTime = millis();     // Record when the tone started
}

void stopTone() {
  noTone(buzzerPin);           // Stop playing the tone
  tonePlaying = false;         // Reset tone playing flag
}

void setup() {
  // Initialize the LCD
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("HUNTER Game");
  delay(2000);  // Display the welcome message for 2 seconds

  // Pin configurations
  for (int i = 0; i < 10; i++) {
    pinMode(ledPins[i], OUTPUT);  // Set all LED pins as outputs
  }
  pinMode(buttonPin, INPUT_PULLUP);  // Set button pin as input with pullup
  pinMode(buzzerPin, OUTPUT);  // Set buzzer pin as output
  
  Serial.begin(9600);  // Start serial for debugging
  Serial.println("Welcome to the Knight Rider Hunter Game!");
  
  lcd.clear();
  displayStatus();  // Display the initial level, score, and time
  startTime = millis();  // Record when the level starts
  lastMoveTime = millis();  // Initialize the last move time
}

void loop() {
  // If the game has ended, stop further operations
  if (gameEnded) {
    return;
  }

  // Check if the timer has expired
  unsigned long elapsedTime = (millis() - startTime) / 1000;
  int remainingTime = levelTime - elapsedTime;

  // If time has run out, end the game
  if (remainingTime <= 0) {
    endGame();  // Call the function to end the game
    return;     // Stop further execution
  }

  // Handle LED movement (non-blocking using millis)
  if (millis() - lastMoveTime >= delayTime) {
    moveLED();
    lastMoveTime = millis();  // Reset the last move time
    startTone(1000);  // Start playing the 1000Hz tone when moving LED
  }

  // Stop the tone after 50ms
  if (tonePlaying && millis() - lastToneTime >= 50) {
    stopTone();  // Stop the tone after 50ms
  }

  // Check if the button is pressed (with debouncing)
  int buttonState = digitalRead(buttonPin);
  if (buttonState == LOW && millis() - buttonDebounceTime > debounceDelay) {
    buttonDebounceTime = millis();  // Reset debounce timer
    if (currentLED == middleLED) {
      Serial.println("You win this level!");
      score++;  // Increase score for a successful hit
      startTone(2000);  // Play victory tone
      delay(500);  // Play for 500ms
      stopTone();
      levelUp();  // Go to the next level
    } else {
      Serial.println("Missed! Try again.");
      startTone(500);  // Play fail sound
      delay(300);  // Play for 300ms
      stopTone();
    }
    delay(500);  // Short pause after button press
  }

  // Update LCD with the remaining time and score only if there's a change
  if (remainingTime != lastRemainingTime || level != lastLevel || score != lastScore) {
    displayStatus();
    lastRemainingTime = remainingTime;
    lastLevel = level;
    lastScore = score;
  }
}

// Function to move the LEDs
void moveLED() {
  // Turn off all LEDs
  for (int i = 0; i < 10; i++) {
    digitalWrite(ledPins[i], LOW);
  }

  // Light up the current LED
  digitalWrite(ledPins[currentLED], HIGH);

  // Move the LED in the current direction
  currentLED += direction;

  // Reverse direction if we reach the end of the LED array
  if (currentLED == 9 || currentLED == 0) {
    direction = -direction;
  }
}

// Function to advance to the next level
void levelUp() {
  level++;  // Increase the level
  delayTime -= 30;  // Decrease delay time to make LEDs move faster

  // Ensure delayTime doesn't go below a certain threshold (e.g., 50 ms)
  if (delayTime < 50) {
    delayTime = 50;
  }

  Serial.print("Level Up! Now at Level: ");
  Serial.println(level);
  Serial.print("New LED Speed (ms): ");
  Serial.println(delayTime);

  // Play level-up sound
  startTone(1500);  // Play a tone at 1.5kHz
  delay(300);       // Play for 300ms
  stopTone();
  delay(1000);  // Give a 1-second pause before starting the next level

  // Reset the timer for the next level
  startTime = millis();
}

// Function to display the current level, score, and remaining time
void displayStatus() {
  // Calculate the remaining time in seconds
  unsigned long elapsedTime = (millis() - startTime) / 1000;  // Convert to seconds
  int remainingTime = levelTime - elapsedTime;  // Calculate the remaining time
  
  // Ensure the remaining time does not go negative
  if (remainingTime < 0) {
    remainingTime = 0;
  }
  
  lcd.setCursor(0, 0);
  lcd.print("Lvl:");
  lcd.print(level);

  lcd.setCursor(6, 0);
  lcd.print("Time:");
  lcd.print(remainingTime);  // Correctly print the remaining time in seconds
  
  // Clear any leftover characters by overwriting with a space
  if (remainingTime < 10) {
    lcd.print(" ");  // Overwrite the extra digit when remainingTime is a single digit
  }

  lcd.setCursor(0, 1);
  lcd.print("Score:");
  lcd.print(score);
}



// Function to end the game when the timer runs out
void endGame() {
  gameEnded = true;  // Set the flag to end the game

  // Turn off all LEDs
  for (int i = 0; i < 8; i++) {
    digitalWrite(ledPins[i], LOW);
  }

  // Display "End Game" and the final score on the LCD
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("End Game");
  lcd.setCursor(0, 1);
  lcd.print("Score:");
  lcd.print(score);

  // Play a sound to indicate the game has ended
  startTone(300);  // Play a low tone
  delay(1000);     // Play for 1 second
  stopTone();

  // Wait for 3 seconds before starting a new game
  delay(3000);

  // Restart the game
  resetGame();
}

// Function to reset the game and start a new one
void resetGame() {
  gameEnded = false;  // Reset the game end flag
  score = 0;          // Reset the score to 0
  level = 1;          // Reset the level to 1
  delayTime = 300;    // Reset the delay time for LED movement
  startTime = millis();  // Reset the timer

  // Clear the LCD and display the initial status
  lcd.clear();
  displayStatus();

  Serial.println("New game started!");
  
  // Restart the LED movement immediately
  lastMoveTime = millis();
}

Credits

Mirko Pavleski
187 projects • 1450 followers

Comments