#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
const int buttonUp = 2; // Enter/Exit game
const int buttonDown = 3;
const int buttonLeft = 4;
const int buttonRight = 5;
const int buttonA = 6; // Move up
const int buttonX = 7; // Move down
const int buttonB = 1; // Move left
const int buttonC = 12; // Move right
const int tileWidth = 100;
const int tileHeight = 80;
const int tilesPerRow = 2;
const int tilesPerColumn = 2;
int selectedTile = 0;
int currentGame = -1;
bool gameOver = false;
uint16_t colors[] = {ILI9341_RED, ILI9341_GREEN, ILI9341_BLUE, ILI9341_YELLOW, ILI9341_MAGENTA, ILI9341_CYAN};
const char* labels[] = {"Pong", "Snake", "Flappy", "Dodger", "Asteroid", "Frogger"};
// Define custom colors
#define LIGHT_GRAY 0xC618
#define GRAY 0x8410
#define DARK_GRAY 0x4208
#define BROWN 0xA145
// Game variables for Pong
int pongPaddleX = 10;
int pongPaddleY = 110;
int pongPaddleHeight = 40;
int pongBallX = 160;
int pongBallY = 120;
int pongBallDX = 2;
int pongBallDY = 2;
// Game variables for Snake
int snakeX = 160;
int snakeY = 120;
int snakePrevX = 160;
int snakePrevY = 120;
int foodX;
int foodY;
bool foodEaten = true;
// Game variables for Flappy Bird
int flappyBirdX = 50;
int flappyBirdY = 120;
int flappyBirdPrevY = 120;
int flappyBirdDY = 0;
int tubeX = 320;
int tubeGapY = 100;
const int tubeWidth = 20;
const int tubeGapHeight = 50;
const int tubeSpeed = 2;
int flappyScore = 0;
// Game variables for Dodger
int dodgerX = 160;
int dodgerY = 120;
int dodgerPrevX = 160;
int dodgerPrevY = 120;
int dodgerObstacleX = 160;
int dodgerObstacleY = 0;
int dodgerObstaclePrevY = 0;
int dodgerObstacleSpeed = 2;
// Game variables for Asteroid Dodger
int asteroidX = 160;
int asteroidY = 120;
int asteroidPrevX = 160;
int asteroidPrevY = 120;
int asteroidSpeed = 3;
int spaceshipX = 160;
int spaceshipY = 200;
// Game variables for Frogger
int frogX = 160;
int frogY = 220;
int frogPrevX = 160;
int frogPrevY = 220;
int car1X = 0;
int car1Y = 180;
int car2X = 160;
int car2Y = 140;
int log1X = 80;
int log1Y = 100;
int log2X = 240;
int log2Y = 60;
int frogLives = 3;
void setup() {
pinMode(buttonUp, INPUT_PULLUP);
pinMode(buttonDown, INPUT_PULLUP);
pinMode(buttonLeft, INPUT_PULLUP);
pinMode(buttonRight, INPUT_PULLUP);
pinMode(buttonA, INPUT_PULLUP);
pinMode(buttonX, INPUT_PULLUP);
pinMode(buttonB, INPUT_PULLUP);
pinMode(buttonC, INPUT_PULLUP);
tft.begin();
tft.setRotation(3); // Set rotation if needed
drawMenu();
}
void loop() {
if (currentGame == -1) {
handleMenuInput();
} else if (!gameOver) {
handleGameInput();
updateGame();
} else {
if (!digitalRead(buttonUp)) {
gameOver = false;
currentGame = -1;
drawMenu();
delay(200); // Debounce delay
}
}
delay(100);
}
void drawMenu() {
tft.fillScreen(ILI9341_WHITE);
for (int i = 0; i < 6; i++) {
int x = (i % tilesPerRow) * tileWidth + 10;
int y = (i / tilesPerRow) * tileHeight + 10;
tft.fillRect(x, y, tileWidth - 10, tileHeight - 10, colors[i]);
if (i == selectedTile) {
tft.drawRect(x - 2, y - 2, tileWidth - 6, tileHeight - 6, ILI9341_BLACK);
}
// Draw label
tft.setCursor(x + 5, y + tileHeight - 25);
tft.setTextColor(ILI9341_BLACK);
tft.setTextSize(2);
tft.print(labels[i]);
// Placeholder for icon (draw a simple shape)
tft.fillCircle(x + tileWidth / 2 - 5, y + tileHeight / 2 - 20, 10, ILI9341_BLACK);
}
}
void handleMenuInput() {
if (!digitalRead(buttonUp)) {
currentGame = selectedTile;
initializeGame();
delay(200); // Debounce delay
}
if (!digitalRead(buttonDown)) {
if (selectedTile < 6 - tilesPerRow) {
selectedTile += tilesPerRow;
drawMenu();
}
}
if (!digitalRead(buttonLeft)) {
if (selectedTile % tilesPerRow > 0) {
selectedTile -= 1;
drawMenu();
}
}
if (!digitalRead(buttonRight)) {
if (selectedTile % tilesPerRow < tilesPerRow - 1) {
selectedTile += 1;
drawMenu();
}
}
}
void initializeGame() {
if (currentGame == 0) {
// Initialize Pong
pongPaddleX = 10;
pongPaddleY = 110;
pongBallX = 160;
pongBallY = 120;
pongBallDX = 2;
pongBallDY = 2;
tft.fillScreen(LIGHT_GRAY); // Set Pong background color
drawPong();
} else if (currentGame == 1) {
// Initialize Snake
snakeX = 160;
snakeY = 120;
snakePrevX = snakeX;
snakePrevY = snakeY;
foodEaten = true;
tft.fillScreen(ILI9341_GREEN); // Set Snake background color
drawSnake();
} else if (currentGame == 2) {
// Initialize Flappy Bird
flappyBirdX = 50;
flappyBirdY = 120;
flappyBirdPrevY = flappyBirdY;
flappyBirdDY = 0;
tubeX = 320;
tubeGapY = random(50, 190);
flappyScore = 0;
tft.fillScreen(ILI9341_CYAN); // Set Flappy Bird background color
drawFlappy();
} else if (currentGame == 3) {
// Initialize Dodger
dodgerX = 160;
dodgerY = 120;
dodgerPrevX = dodgerX;
dodgerPrevY = dodgerY;
dodgerObstacleX = 160;
dodgerObstacleY = 0;
dodgerObstaclePrevY = dodgerObstacleY;
dodgerObstacleSpeed = 2;
tft.fillScreen(ILI9341_BLUE); // Set Dodger background color
drawDodger();
} else if (currentGame == 4) {
// Initialize Asteroid Dodger
asteroidX = random(0, 320);
asteroidY = 0;
spaceshipX = 160;
spaceshipY = 200;
tft.fillScreen(DARK_GRAY); // Set Asteroid Dodger background color
drawAsteroid();
} else if (currentGame == 5) {
// Initialize Frogger
frogX = 160;
frogY = 220;
frogLives = 3;
car1X = 0;
car2X = 160;
log1X = 80;
log2X = 240;
tft.fillScreen(ILI9341_CYAN); // Set Frogger background color
drawFrogger();
}
}
void handleGameInput() {
if (!digitalRead(buttonUp)) {
currentGame = -1;
drawMenu();
delay(200); // Debounce delay
} else if (currentGame == 0) {
// Pong controls
if (!digitalRead(buttonA) && pongPaddleY > 0) {
pongPaddleY -= 5;
drawPong();
}
if (!digitalRead(buttonX) && pongPaddleY < (240 - pongPaddleHeight)) {
pongPaddleY += 5;
drawPong();
}
} else if (currentGame == 1) {
// Snake controls
snakePrevX = snakeX;
snakePrevY = snakeY;
if (!digitalRead(buttonA)) {
snakeY -= 5; // Move up
}
if (!digitalRead(buttonX)) {
snakeY += 5; // Move down
}
if (!digitalRead(buttonB)) {
snakeX -= 5; // Move left
}
if (!digitalRead(buttonC)) {
snakeX += 5; // Move right
}
drawSnake();
} else if (currentGame == 2) {
// Flappy Bird controls
if (!digitalRead(buttonA)) {
flappyBirdDY = -5; // Flap up
}
} else if (currentGame == 3) {
// Dodger controls
dodgerPrevX = dodgerX;
dodgerPrevY = dodgerY;
if (!digitalRead(buttonA) && dodgerY > 0) {
dodgerY -= 5; // Move up
drawDodger();
}
if (!digitalRead(buttonX) && dodgerY < (240 - 10)) {
dodgerY += 5; // Move down
drawDodger();
}
if (!digitalRead(buttonB) && dodgerX > 0) {
dodgerX -= 5; // Move left
drawDodger();
}
if (!digitalRead(buttonC) && dodgerX < (320 - 10)) {
dodgerX += 5; // Move right
drawDodger();
}
} else if (currentGame == 4) {
// Asteroid Dodger controls
if (!digitalRead(buttonB) && spaceshipX > 0) {
spaceshipX -= 5; // Move left
drawAsteroid();
}
if (!digitalRead(buttonC) && spaceshipX < (320 - 10)) {
spaceshipX += 5; // Move right
drawAsteroid();
}
} else if (currentGame == 5) {
// Frogger controls
frogPrevX = frogX;
frogPrevY = frogY;
if (!digitalRead(buttonA) && frogY > 0) {
frogY -= 20; // Move up
drawFrogger();
}
if (!digitalRead(buttonX) && frogY < (240 - 20)) {
frogY += 20; // Move down
drawFrogger();
}
if (!digitalRead(buttonB) && frogX > 0) {
frogX -= 20; // Move left
drawFrogger();
}
if (!digitalRead(buttonC) && frogX < (320 - 20)) {
frogX += 20; // Move right
drawFrogger();
}
}
}
void updateGame() {
if (currentGame == 0) {
updatePong();
} else if (currentGame == 1) {
updateSnake();
} else if (currentGame == 2) {
updateFlappy();
} else if (currentGame == 3) {
updateDodger();
} else if (currentGame == 4) {
updateAsteroid();
} else if (currentGame == 5) {
updateFrogger();
}
}
void drawPong() {
tft.fillScreen(LIGHT_GRAY); // Clear screen
tft.fillRect(pongPaddleX, pongPaddleY, 5, pongPaddleHeight, ILI9341_WHITE); // Draw paddle
tft.fillRect(pongBallX, pongBallY, 5, 5, ILI9341_WHITE); // Draw ball
}
void updatePong() {
tft.fillRect(pongBallX, pongBallY, 5, 5, LIGHT_GRAY); // Clear previous ball position
pongBallX += pongBallDX;
pongBallY += pongBallDY;
if (pongBallX <= pongPaddleX + 5 && pongBallY >= pongPaddleY && pongBallY <= pongPaddleY + pongPaddleHeight) {
pongBallDX = -pongBallDX; // Ball hits paddle
}
if (pongBallX <= 0 || pongBallX >= 320) {
pongBallDX = -pongBallDX; // Ball hits wall
}
if (pongBallY <= 0 || pongBallY >= 240) {
pongBallDY = -pongBallDY; // Ball hits top/bottom
}
tft.fillRect(pongBallX, pongBallY, 5, 5, ILI9341_WHITE); // Draw new ball position
tft.fillRect(pongPaddleX, pongPaddleY, 5, pongPaddleHeight, ILI9341_WHITE); // Draw paddle
// Game over condition
if (pongBallX <= 0) {
displayGameOver();
}
}
void drawSnake() {
tft.fillRect(snakePrevX, snakePrevY, 10, 10, ILI9341_GREEN); // Clear previous snake position
tft.fillRect(snakeX, snakeY, 10, 10, ILI9341_WHITE); // Draw new snake position
if (foodEaten) {
spawnFood();
}
tft.fillRect(foodX, foodY, 10, 10, ILI9341_RED); // Draw food
}
void updateSnake() {
tft.fillRect(snakePrevX, snakePrevY, 10, 10, ILI9341_GREEN); // Clear previous snake position
drawSnake();
// Game over condition
if (snakeX < 0 || snakeX >= 320 || snakeY < 0 || snakeY >= 240) {
displayGameOver();
}
}
void spawnFood() {
foodX = (random(0, 320 / 10)) * 10;
foodY = (random(0, 240 / 10)) * 10;
foodEaten = false;
}
void drawFlappy() {
tft.fillScreen(ILI9341_CYAN); // Clear screen
tft.fillRect(flappyBirdX, flappyBirdY, 10, 10, ILI9341_YELLOW); // Draw bird
tft.fillRect(tubeX, 0, tubeWidth, tubeGapY, ILI9341_GREEN); // Draw top tube
tft.fillRect(tubeX, tubeGapY + tubeGapHeight, tubeWidth, 240 - tubeGapY - tubeGapHeight, ILI9341_GREEN); // Draw bottom tube
}
void updateFlappy() {
tft.fillRect(flappyBirdX, flappyBirdPrevY, 10, 10, ILI9341_CYAN); // Clear previous bird position
flappyBirdY += flappyBirdDY;
flappyBirdDY += 1; // Gravity
tft.fillRect(flappyBirdX, flappyBirdY, 10, 10, ILI9341_YELLOW); // Draw new bird position
flappyBirdPrevY = flappyBirdY;
// Move and redraw tubes
tft.fillRect(tubeX, 0, tubeWidth, tubeGapY, ILI9341_CYAN); // Clear previous top tube
tft.fillRect(tubeX, tubeGapY + tubeGapHeight, tubeWidth, 240 - tubeGapY - tubeGapHeight, ILI9341_CYAN); // Clear previous bottom tube
tubeX -= tubeSpeed;
if (tubeX < -tubeWidth) {
tubeX = 320;
tubeGapY = random(50, 190);
flappyScore++;
}
tft.fillRect(tubeX, 0, tubeWidth, tubeGapY, ILI9341_GREEN); // Draw new top tube
tft.fillRect(tubeX, tubeGapY + tubeGapHeight, tubeWidth, 240 - tubeGapY - tubeGapHeight, ILI9341_GREEN); // Draw new bottom tube
// Check for collisions
if (flappyBirdX >= tubeX && flappyBirdX <= tubeX + tubeWidth) {
if (flappyBirdY <= tubeGapY || flappyBirdY >= tubeGapY + tubeGapHeight) {
displayGameOver();
return;
}
}
// Game over condition
if (flappyBirdY >= 240 || flappyBirdY <= 0) {
displayGameOver();
return;
}
// Win condition
if (flappyScore >= 10) {
displayWin();
}
}
void drawDodger() {
tft.fillScreen(ILI9341_BLUE); // Clear screen
tft.fillRect(dodgerX, dodgerY, 10, 10, ILI9341_RED); // Draw dodger
tft.fillRect(dodgerObstacleX, dodgerObstacleY, 10, 10, ILI9341_WHITE); // Draw obstacle
}
void updateDodger() {
tft.fillRect(dodgerObstacleX, dodgerObstaclePrevY, 10, 10, ILI9341_BLUE); // Clear previous obstacle position
dodgerObstacleY += dodgerObstacleSpeed;
if (dodgerObstacleY >= 240) {
dodgerObstacleY = 0;
dodgerObstacleX = random(0, 320);
}
tft.fillRect(dodgerObstacleX, dodgerObstacleY, 10, 10, ILI9341_WHITE); // Draw new obstacle position
dodgerObstaclePrevY = dodgerObstacleY;
tft.fillRect(dodgerX, dodgerY, 10, 10, ILI9341_RED); // Draw dodger
// Game over condition
if (dodgerX == dodgerObstacleX && dodgerY == dodgerObstacleY) {
displayGameOver();
}
}
void drawAsteroid() {
tft.fillScreen(DARK_GRAY); // Clear screen
tft.fillRect(spaceshipX, spaceshipY, 10, 10, ILI9341_WHITE); // Draw spaceship
tft.fillRect(asteroidX, asteroidY, 10, 10, GRAY); // Draw asteroid
}
void updateAsteroid() {
tft.fillRect(asteroidX, asteroidY, 10, 10, DARK_GRAY); // Clear previous asteroid position
asteroidY += asteroidSpeed;
if (asteroidY >= 240) {
asteroidY = 0;
asteroidX = random(0, 320);
}
tft.fillRect(asteroidX, asteroidY, 10, 10, GRAY); // Draw new asteroid position
tft.fillRect(spaceshipX, spaceshipY, 10, 10, ILI9341_WHITE); // Draw spaceship
// Game over condition
if (spaceshipX == asteroidX && spaceshipY == asteroidY) {
displayGameOver();
}
}
void drawFrogger() {
tft.fillScreen(ILI9341_CYAN); // Clear screen
tft.fillRect(frogX, frogY, 10, 10, ILI9341_GREEN); // Draw frog
tft.fillRect(car1X, car1Y, 30, 20, ILI9341_RED); // Draw car 1
tft.fillRect(car2X, car2Y, 30, 20, ILI9341_RED); // Draw car 2
tft.fillRect(log1X, log1Y, 60, 20, BROWN); // Draw log 1
tft.fillRect(log2X, log2Y, 60, 20, BROWN); // Draw log 2
// Draw home (house)
tft.fillRect(150, 0, 20, 20, ILI9341_BLUE);
}
void updateFrogger() {
tft.fillRect(frogPrevX, frogPrevY, 10, 10, ILI9341_CYAN); // Clear previous frog position
tft.fillRect(car1X, car1Y, 30, 20, ILI9341_CYAN); // Clear previous car 1 position
tft.fillRect(car2X, car2Y, 30, 20, ILI9341_CYAN); // Clear previous car 2 position
tft.fillRect(log1X, log1Y, 60, 20, ILI9341_CYAN); // Clear previous log 1 position
tft.fillRect(log2X, log2Y, 60, 20, ILI9341_CYAN); // Clear previous log 2 position
// Update positions
car1X += 2;
car2X -= 2;
log1X += 1;
log2X -= 1;
// Wrap around
if (car1X >= 320) car1X = -30;
if (car2X <= -30) car2X = 320;
if (log1X >= 320) log1X = -60;
if (log2X <= -60) log2X = 320;
// Check for collisions
if ((frogY == car1Y && frogX >= car1X && frogX <= car1X + 30) ||
(frogY == car2Y && frogX >= car2X && frogX <= car2X + 30)) {
frogX = 160;
frogY = 220;
frogLives--;
if (frogLives == 0) {
displayGameOver();
return;
}
}
// Win condition
if (frogY <= 20 && frogX >= 150 && frogX <= 170) {
displayWin();
return;
}
// Draw new positions
tft.fillRect(frogX, frogY, 10, 10, ILI9341_GREEN); // Draw frog
tft.fillRect(car1X, car1Y, 30, 20, ILI9341_RED); // Draw car 1
tft.fillRect(car2X, car2Y, 30, 20, ILI9341_RED); // Draw car 2
tft.fillRect(log1X, log1Y, 60, 20, BROWN); // Draw log 1
tft.fillRect(log2X, log2Y, 60, 20, BROWN); // Draw log 2
// Draw home (house)
tft.fillRect(150, 0, 20, 20, ILI9341_BLUE);
}
void displayGameOver() {
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(3);
tft.setCursor(60, 100);
tft.print("Game Over");
gameOver = true;
}
void displayWin() {
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(3);
tft.setCursor(60, 100);
tft.print("You Win!");
gameOver = true;
}