#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <pgmspace.h>
// TFT display connections
#define TFT_CS D0
#define TFT_RST D2
#define TFT_DC D1
// Button connections
#define BUTTON_LEFT A3
#define BUTTON_RIGHT A4
#define BUTTON_SHOOT A5
// Define threshold for touch sensitivity
#define TOUCH_THRESHOLD 30
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
struct Object {
int16_t x, y;
uint16_t color;
bool active;
};
struct Projectile {
int16_t x, y;
bool active;
};
struct Explosion {
int16_t x, y;
uint8_t frame;
bool active;
};
Object enemies[15];
Projectile bullets[10];
Projectile enemyBullets[10];
Explosion explosions[5];
int16_t paddleX = 130; // Initial paddle position (shifted right)
int score = 0;
int lives = 3;
int level = 1;
bool gameOver = false;
uint8_t direction = 0; // 0 for right, 1 for left
void setupEnemies() {
for (int i = 0; i < 15; i++) {
uint16_t color;
if (i < 5) {
color = ILI9341_RED;
} else if (i < 10) {
color = ILI9341_GREEN;
} else {
color = ILI9341_BLUE;
}
enemies[i] = { random(30, 190), random(-320, 0), color, true }; // Shifted right
}
}
void moveEnemies() {
for (int i = 0; i < 15; i++) {
if (enemies[i].active) {
enemies[i].y += (i % 3 == 0) ? 1 : 2; // Different speeds for different enemies
if (enemies[i].y > 320) {
enemies[i].y = random(-320, 0);
enemies[i].x = random(30, 190); // Shifted right
}
if (random(0, 100) < 3) {
for (int j = 0; j < 10; j++) {
if (!enemyBullets[j].active) {
enemyBullets[j] = { enemies[i].x + 5, enemies[i].y + 10, true };
break;
}
}
}
}
}
}
void drawEnemies() {
for (int i = 0; i < 15; i++) {
if (enemies[i].active) {
tft.fillRect(enemies[i].x, enemies[i].y, 10, 10, enemies[i].color);
}
}
}
void moveBullets() {
for (int i = 0; i < 10; i++) {
if (bullets[i].active) {
bullets[i].y -= 5;
if (bullets[i].y < 0) {
bullets[i].active = false;
}
for (int j = 0; j < 15; j++) {
if (enemies[j].active && bullets[i].x > enemies[j].x && bullets[i].x < enemies[j].x + 10 && bullets[i].y > enemies[j].y && bullets[i].y < enemies[j].y + 10) {
bullets[i].active = false;
enemies[j].active = false;
score += 10;
// Trigger explosion
for (int k = 0; k < 5; k++) {
if (!explosions[k].active) {
explosions[k] = { enemies[j].x + 5, enemies[j].y + 5, 0, true };
break;
}
}
if (score % 150 == 0) {
level++;
}
}
}
}
if (enemyBullets[i].active) {
enemyBullets[i].y += 3;
if (enemyBullets[i].y > 320) {
enemyBullets[i].active = false;
}
if (enemyBullets[i].x > paddleX && enemyBullets[i].x < paddleX + 20 && enemyBullets[i].y > 240 && enemyBullets[i].y < 250) {
enemyBullets[i].active = false;
lives--;
if (lives <= 0) {
gameOver = true;
}
}
}
}
}
void drawBullets() {
for (int i = 0; i < 10; i++) {
if (bullets[i].active) {
tft.fillRect(bullets[i].x, bullets[i].y, 2, 5, ILI9341_WHITE);
}
if (enemyBullets[i].active) {
tft.fillRect(enemyBullets[i].x, enemyBullets[i].y, 2, 5, ILI9341_YELLOW);
}
}
}
// Adjusted Background Drawing to use the entire screen
void drawBackground() {
tft.fillScreen(ILI9341_BLACK);
for (int y = 0; y < 320; y += 20) {
for (int x = 20; x < 240; x += 20) { // Shifted right
if (random(0, 10) < 2) {
tft.drawPixel(x + random(0, 20), y + random(0, 20), ILI9341_WHITE);
}
}
}
}
// Adjusted UI Panel Positioning to use the full screen width
void drawUI() {
tft.fillRect(210, 0, 30, 320, ILI9341_DARKGREY);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.setCursor(215, 10);
tft.print("Lives:");
for (int i = 0; i < lives; i++) {
tft.fillRect(215, 20 + i * 10, 10, 10, ILI9341_RED);
}
tft.setCursor(215, 70);
tft.print("Score:");
tft.setCursor(215, 80);
tft.print(score);
tft.setCursor(215, 100);
tft.print("Level:");
tft.setCursor(215, 110);
tft.print(level);
}
void drawExplosions() {
for (int i = 0; i < 5; i++) {
if (explosions[i].active) {
int16_t x = explosions[i].x;
int16_t y = explosions[i].y;
uint8_t frame = explosions[i].frame;
uint16_t color = (frame % 2 == 0) ? ILI9341_YELLOW : ILI9341_RED;
tft.drawCircle(x, y, frame * 2, color);
explosions[i].frame++;
if (explosions[i].frame > 5) {
explosions[i].active = false;
}
}
}
}
// Adjusted Spaceship Position to be higher up
void drawSpaceship(int16_t x, int16_t y) {
tft.fillTriangle(x, y, x + 15, y + 25, x - 15, y + 25, ILI9341_WHITE); // Wider spaceship
}
void setup() {
tft.begin();
tft.setRotation(1);
drawBackground();
setupEnemies();
pinMode(BUTTON_LEFT, INPUT);
pinMode(BUTTON_RIGHT, INPUT);
pinMode(BUTTON_SHOOT, INPUT);
}
void loop() {
if (!gameOver) {
drawBackground();
drawEnemies();
drawBullets();
drawExplosions();
drawSpaceship(paddleX + 15, 230); // Draw spaceship higher up
drawUI();
moveEnemies();
moveBullets();
// Read touch states and compare with threshold
if (touchRead(BUTTON_LEFT) < TOUCH_THRESHOLD) {
paddleX -= 2;
if (paddleX <= 30) paddleX = 30;
}
if (touchRead(BUTTON_RIGHT) < TOUCH_THRESHOLD) {
paddleX += 2;
if (paddleX >= 190) paddleX = 190;
}
if (touchRead(BUTTON_SHOOT) < TOUCH_THRESHOLD) {
for (int i = 0; i < 10; i++) {
if (!bullets[i].active) {
bullets[i] = {paddleX + 15, 220, true};
break;
}
}
}
delay(50);
} else {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(50, 140);
tft.setTextColor(ILI9341_RED);
tft.setTextSize(2);
tft.print("Game Over!");
tft.setCursor(50, 180);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.print("Score: ");
tft.print(score);
}
}