#include <Adafruit_ILI9341.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Arduino.h>


// Pin definitions
#define TFT_CS    27
#define TFT_DC    26
#define TFT_RST   25
#define TFT_CLK   13
#define TFT_MISO  12
#define TFT_MOSI  14
#define TFT_LED   33
#define LEFT_BUTTON_PIN 22
#define RIGHT_BUTTON_PIN 23

// TFT screen dimensions
#define TFT_WIDTH  320
#define TFT_HEIGHT 240

// Runway properties
#define RUNWAY_WIDTH  TFT_WIDTH / 3
#define RUNWAY_HEIGHT TFT_HEIGHT

// Player dimensions
#define PLAYER_WIDTH  20
#define PLAYER_HEIGHT 20

// Obstacle dimensions
#define OBSTACLE_WIDTH  20
#define OBSTACLE_HEIGHT 20

// Global variables
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST, TFT_CLK, TFT_MISO, TFT_MOSI);
int playerX;
int playerY;
int currentRunway = 0;
int lives = 3;

void setupTFT() {
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);
   pinMode(TFT_LED, OUTPUT);
  digitalWrite(TFT_LED, HIGH); // Turn on the backlight

}

void clearObstacle(int x, int y) {
  tft.fillRect(x, y, OBSTACLE_WIDTH, OBSTACLE_HEIGHT, ILI9341_BLACK);
}

void setupPlayer() {
  playerX = (RUNWAY_WIDTH - PLAYER_WIDTH) / 2;
  playerY = TFT_HEIGHT - PLAYER_HEIGHT;
  tft.fillRect(playerX, playerY, PLAYER_WIDTH, PLAYER_HEIGHT, ILI9341_YELLOW);
}

void updatePlayerPosition() {
  if (digitalRead(LEFT_BUTTON_PIN) == LOW) {
    currentRunway = (currentRunway + 2) % 3;
  }
  if (digitalRead(RIGHT_BUTTON_PIN) == LOW) {
    currentRunway = (currentRunway + 1) % 3;
  }
  tft.fillRect(playerX, playerY, PLAYER_WIDTH, PLAYER_HEIGHT, ILI9341_BLACK);
  playerX = currentRunway * RUNWAY_WIDTH + (RUNWAY_WIDTH - PLAYER_WIDTH) / 2;
  tft.fillRect(playerX, playerY, PLAYER_WIDTH, PLAYER_HEIGHT, ILI9341_YELLOW);
}

void drawObstacle(int x, int y) {
  tft.fillRect(x, y, OBSTACLE_WIDTH, OBSTACLE_HEIGHT, ILI9341_RED);
}

bool checkCollision(int obstacleX, int obstacleY) {
  if (playerX + PLAYER_WIDTH >= obstacleX && playerX <= obstacleX + OBSTACLE_WIDTH &&
      playerY + PLAYER_HEIGHT >= obstacleY && playerY <= obstacleY + OBSTACLE_HEIGHT) {
    return true;
  }
  return false;
}

void gameOver() {
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(TFT_WIDTH / 2 - 50, TFT_HEIGHT / 2 - 10);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(3);
  tft.println("Game Over");
  while (true) {
    // Endless loop to keep the "Game Over" message on the screen
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(LEFT_BUTTON_PIN, INPUT_PULLUP);
  pinMode(RIGHT_BUTTON_PIN, INPUT_PULLUP);
  setupTFT();
  setupPlayer();
  pinMode(TFT_LED, OUTPUT);
  digitalWrite(TFT_LED, HIGH); // Turn on the backlight

}

void loop() {
  updatePlayerPosition();
  int obstacleX = random(currentRunway * RUNWAY_WIDTH, (currentRunway + 1) * RUNWAY_WIDTH - OBSTACLE_WIDTH);
  int obstacleY = 0;
  drawObstacle(obstacleX, obstacleY);
  while (obstacleY < TFT_HEIGHT) {
    if (checkCollision(obstacleX, obstacleY)) {
      lives--;
      if (lives == 0) {
        gameOver();
      }
    }
    obstacleY++;
    clearObstacle(obstacleX, obstacleY - OBSTACLE_HEIGHT);
    drawObstacle(obstacleX, obstacleY);
    delay(100);
  }
}