#include <Adafruit_GFX.h> // Include the Adafruit Graphics Library
#include <Adafruit_ILI9341.h> // Include the Adafruit ILI9341 Library
#define TFT_CS 15
#define TFT_RST 2
#define TFT_DC 4
#define UP_BUTTON 13
#define DOWN_BUTTON 12
#define LEFT_BUTTON 14
#define RIGHT_BUTTON 27
#define SHOOT_BUTTON 17
#define CROSSHAIR_SPEED 6 // Increase crosshair speed to 6 pixels per movement
// Define difficulty levels
enum Difficulty {
EASY,
NORMAL,
HARD,
NUM_DIFFICULTIES // Add a new enum value for the number of difficulties
};
Difficulty selectedDifficulty = EASY; // Default difficulty
bool difficultySelected = false; // Flag to track if difficulty is selected
// Structure to store spot information
struct Spot {
int x; // X-coordinate
int y; // Y-coordinate
bool active; // Flag to indicate if spot is active
};
const int MAX_SPOTS = 1000; // Maximum number of spots
Spot spots[MAX_SPOTS]; // Array to store spots
int crosshairX = 120; // Initial X-coordinate of the crosshair
int crosshairY = 160; // Initial Y-coordinate of the crosshair
int prevCrosshairX = crosshairX; // Previous X-coordinate of the crosshair
int prevCrosshairY = crosshairY; // Previous Y-coordinate of the crosshair
int remainingTime = 0; // Remaining time in seconds
unsigned long lastTime = 0; // Last time the timer was updated in milliseconds
unsigned long lastSpawnTime = 0; // Last time a spot was spawned
int spotSpawnIntervals[NUM_DIFFICULTIES] = {1000, 500, 200}; // Intervals between spot spawns for each difficulty (milliseconds)
// Create an instance of the Adafruit ILI9341 TFT LCD display
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
void displayMenu() {
tft.fillScreen(ILI9341_BLACK); // Clear the screen
tft.setTextSize(2); // Set text size
tft.setTextColor(ILI9341_WHITE); // Set text color
// Display difficulty options
tft.setCursor(20, 50);
tft.println("Select Difficulty:");
tft.setCursor(40, 100);
if (selectedDifficulty == EASY) {
tft.print(">");
}
tft.print("1. Easy");
if (selectedDifficulty == EASY) {
tft.print(" (Selected)");
}
tft.setCursor(40, 130);
if (selectedDifficulty == NORMAL) {
tft.print(">");
}
tft.print("2. Normal");
if (selectedDifficulty == NORMAL) {
tft.print(" (Selected)");
}
tft.setCursor(40, 160);
if (selectedDifficulty == HARD) {
tft.print(">");
}
tft.print("3. Hard");
if (selectedDifficulty == HARD) {
tft.print(" (Selected)");
}
}
void clearSpot(int index) {
tft.fillCircle(spots[index].x, spots[index].y, 10, ILI9341_BLACK); // Increase radius to 10 pixels
spots[index].active = false; // Mark spot as inactive
}
void setup() {
tft.begin(); // Initialize the display
tft.setRotation(3); // Set display rotation (optional)
pinMode(UP_BUTTON, INPUT_PULLUP); // Set button pins as input with pull-up resistors
pinMode(DOWN_BUTTON, INPUT_PULLUP);
pinMode(LEFT_BUTTON, INPUT_PULLUP);
pinMode(RIGHT_BUTTON, INPUT_PULLUP);
pinMode(SHOOT_BUTTON, INPUT_PULLUP);
displayMenu(); // Display the difficulty menu
// Set initial remaining time to 60 seconds
remainingTime = 60;
}
void loop() {
unsigned long currentTime = millis(); // Get current time in milliseconds
// Update remaining time every second if difficulty is selected
if (difficultySelected && currentTime - lastTime >= 1000) {
lastTime = currentTime;
remainingTime--;
// If remaining time is 0, game over
if (remainingTime == 0) {
// Add game over logic here
}
// Clear previous time display
tft.fillRect(200, 16, 60, 16, ILI9341_BLACK);
// Display remaining time on the top right corner of the screen
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(200, 16);
tft.print(remainingTime);
}
// If difficulty is not selected, handle difficulty selection
if (!difficultySelected) {
if (digitalRead(UP_BUTTON) == LOW) {
selectedDifficulty = static_cast<Difficulty>((selectedDifficulty + 2) % NUM_DIFFICULTIES);
remainingTime = 60; // Set initial remaining time
lastTime = millis(); // Reset last time
displayMenu();
delay(200);
} else if (digitalRead(DOWN_BUTTON) == LOW) {
selectedDifficulty = static_cast<Difficulty>((selectedDifficulty + 1) % NUM_DIFFICULTIES);
remainingTime = 60; // Set initial remaining time
lastTime = millis(); // Reset last time
displayMenu();
delay(200);
} else if (digitalRead(SHOOT_BUTTON) == LOW) {
difficultySelected = true; // Difficulty selected after shoot button is pressed
clearScreen(); // Clear the menu
}
} else {
static int currentSpotIndex = 0; // Index of the current spot being generated
static bool spotCleared = true; // Flag to track if spot is cleared
// Check if spot is cleared and generate new spot if needed
if (spotCleared && currentSpotIndex < MAX_SPOTS && currentTime - lastSpawnTime >= spotSpawnIntervals[selectedDifficulty]) {
// Generate spot if there's room for more spots and enough time has passed since last spawn
spots[currentSpotIndex].x = random(tft.width()); // Generate random x-coordinate within display width
spots[currentSpotIndex].y = random(tft.height()); // Generate random y-coordinate within display height
spots[currentSpotIndex].active = true; // Mark spot as active
tft.fillCircle(spots[currentSpotIndex].x, spots[currentSpotIndex].y, 10, ILI9341_RED); // Draw a red spot
currentSpotIndex++; // Move to the next spot index
spotCleared = false; // Reset spot cleared flag
lastSpawnTime = currentTime; // Update last spawn time
}
// Control the crosshair position using directional buttons
if (digitalRead(UP_BUTTON) == LOW && crosshairY > 0) {
prevCrosshairX = crosshairX;
prevCrosshairY = crosshairY;
crosshairY -= CROSSHAIR_SPEED;
} else if (digitalRead(DOWN_BUTTON) == LOW && crosshairY < tft.height() - 1) {
prevCrosshairX = crosshairX;
prevCrosshairY = crosshairY;
crosshairY += CROSSHAIR_SPEED;
} else if (digitalRead(LEFT_BUTTON) == LOW && crosshairX > 0) {
prevCrosshairX = crosshairX;
prevCrosshairY = crosshairY;
crosshairX -= CROSSHAIR_SPEED;
} else if (digitalRead(RIGHT_BUTTON) == LOW && crosshairX < tft.width() - 1) {
prevCrosshairX = crosshairX;
prevCrosshairY = crosshairY;
crosshairX += CROSSHAIR_SPEED;
}
// Check if the shoot button is pressed and crosshair overlaps with a spot
if (digitalRead(SHOOT_BUTTON) == LOW) {
for (int i = 0; i < MAX_SPOTS; i++) {
if (spots[i].active && abs(crosshairX - spots[i].x) <= 10 && abs(crosshairY - spots[i].y) <= 10) {
clearSpot(i);
spotCleared = true; // Set spot cleared flag
}
}
}
// Redraw the previous position of the crosshair with the background color
tft.drawFastVLine(prevCrosshairX, prevCrosshairY - 10, 21, ILI9341_BLACK); // Vertical line
tft.drawFastHLine(prevCrosshairX - 10, prevCrosshairY, 21, ILI9341_BLACK); // Horizontal line
// Draw the crosshair
tft.drawFastVLine(crosshairX, crosshairY - 10, 21, ILI9341_WHITE); // Vertical line
tft.drawFastHLine(crosshairX - 10, crosshairY, 21, ILI9341_WHITE); // Horizontal line
// Update the previous position of the crosshair
prevCrosshairX = crosshairX;
prevCrosshairY = crosshairY;
}
delay(50); // Introduce delay to prevent rapid spot generation and crosshair movement
}
void clearScreen() {
tft.fillScreen(ILI9341_BLACK); // Clear the screen
}
Loading
esp32-devkit-c-v4
esp32-devkit-c-v4