#include <Adafruit_GFX.h> // 引入Adafruit GFX库
#include <Adafruit_ILI9341.h> // 引入Adafruit ILI9341库
#define TFT_CS 15 // 定义ILI9341晶片选择引脚,使用GPIO15
#define TFT_RST 2 // 定义ILI9341重置引脚,使用GPIO2
#define TFT_DC 4 // 定义ILI9341数据/命令切换引脚,使用GPIO4
#define JOY_X 32 // 定义摇杆的X轴模拟输入引脚,使用GPIO32
#define JOY_Y 33 // 定义摇杆的Y轴模拟输入引脚,使用GPIO33
#define JOY_BUTTON 14 // 定义摇杆按钮引脚,使用GPIO14
#define ENEMY_BULLET_SPEED 10 // 敵人子彈速度
#define ENEMY_BULLET_INTERVAL 2000 // 敵人射擊間隔(毫秒)
#define MAX_ENEMY_BULLETS 10 // 最大敵人子彈數量
// 定义玩家图案的宽度和高度
#define PLAYER_WIDTH 10
#define PLAYER_HEIGHT 25
#define shapeSize 2 // 图形線條大小
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); // 初始化ILI9341显示器
const int arrowSize = 7;
int Difficulty = 0;
int GameState = 0; // 0表示主菜单,1表示选择单人/双人模式,2表示游戏进行中
int arrowX = 50;
int arrowY = 107;
int arrowFX = 50;
int arrowFY = 127;
int prevJoyY = 0;
int prevJoyFY = 0;
int posX = 110; // 图形的初始X坐标
int posY = 290; // 图形的初始Y坐标
int prevX = 110; // 先前图形的X坐标
int prevY = 290; // 先前图形的Y坐标
int enemyX = 60;
int enemyY = -20; // 初始敌人位置在顶部
int enemySize = 20;
int enemySpeed = 7; // 敌人的移动速度
int bulletX[50]; // 子弹的X坐标数组
int bulletY[50]; // 子弹的Y坐标数组
bool bulletHit[50]; // 子弹是否击中敌人的标记数组
int bulletSpeed = 15; // 子弹速度
int bulletCount = 0; // 当前子弹数量
unsigned long lastShootTime = 0; // 上次射击的时间
unsigned long shootInterval = 5000; // 设置为 300 毫秒
unsigned long lastEnemyBulletTime = 0; // 上次敵人射擊的時間
int enemyBulletX[MAX_ENEMY_BULLETS]; // 敵人子彈的 X 坐標
int enemyBulletY[MAX_ENEMY_BULLETS]; // 敵人子彈的 Y 坐標
bool enemyBulletActive[MAX_ENEMY_BULLETS]; // 敵人子彈是否活躍
int enemyBulletCount = 0; // 當前敵人子彈數量
int score = 0; // 声明并初始化得分变量
void setup() {
Serial.begin(9600);
tft.begin();
tft.setRotation(0);
arrowFX = 50;
arrowFY = 127;
prevJoyFY = 0;
// 设置文本大小和颜色
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
// 初始化游戏状态
GameState = 0;
drawMainMenu(); // 绘制主菜单界面
}
void drawArrow(int x, int y) {
tft.fillTriangle(x, y - arrowSize, x + arrowSize, y, x, y + arrowSize, ILI9341_WHITE);
tft.fillRect(x - arrowSize, y - (arrowSize / 2), arrowSize, arrowSize, ILI9341_WHITE);
}
void startGame(int Difficulty) {
tft.fillScreen(ILI9341_BLACK);
initializeGameParameters(Difficulty);
// 初始分数显示
tft.setCursor(0, 0); // 设置光标位置
tft.print("Score: "); // 打印得分标签
tft.print(score); // 打印得分值
// 绘制飞机图片
drawPlayer(posX, posY, ILI9341_WHITE);
drawEnemy(enemyX, enemyY, ILI9341_RED); // 绘制敌人图形
for (int i = 0; i < 50; i++) {
bulletHit[i] = false;
}
}
void initializeGameParameters(int Difficulty) {
switch (Difficulty) {
case 0:
tft.setCursor(90, 100);
tft.print("EASY");
break;
case 1:
tft.setCursor(90, 150);
tft.print("NORMAL");
break;
case 2:
tft.setCursor(90, 200);
tft.print("HARD");
break;
}
}
void loop() {
if (GameState == 1) {
handleJoystick(arrowFY, prevJoyFY, 80, 207, 127);
if (digitalRead(JOY_BUTTON) == HIGH) {
while (digitalRead(JOY_BUTTON) == HIGH);
if (arrowFY == 127) {
GameState = 2; // 进入游戏进行状态
arrowX = 50;
arrowY = 107;
prevJoyY = 0;
drawDifficultySelectionMenu(); // 绘制选择模式界面
} else {
// 如果箭头不在单人模式选项上,什么都不做
}
}
}
if (GameState == 2) {
handleJoystick(arrowY, prevJoyY, 50, 257, 107);
if (digitalRead(JOY_BUTTON) == HIGH) {
while (digitalRead(JOY_BUTTON) == HIGH);
if (arrowY == 107) {
Difficulty = 0; // 简单
back();
} else if (arrowY == 157) {
Difficulty = 1; // 正常
back();
} else if (arrowY == 207) {
Difficulty = 2; // 困难
back();
} else {
setup();
}
}
}
if (GameState == 3) {
// 读取摇杆的X和Y轴值
int joyX = analogRead(JOY_X);
int joyY = analogRead(JOY_Y);
// 将摇杆的值映射到图形移动的范围
int moveX = map(joyX, 0, 4095, 10, -10); // 这里的范围 (10, -10) 可以根据需要调整
int moveY = map(joyY, 0, 4095, 10, -10); // 这里的范围 (10, -10) 可以根据需要调整
// 清除先前的玩家图形
drawPlayer(prevX, prevY, ILI9341_BLACK);
// 更新玩家图形的位置
posX = constrain(posX + moveX, 0, tft.width() - shapeSize); // 考虑到图形大小和屏幕边界
posY = constrain(posY + moveY, 0, tft.height() - shapeSize); // 考虑到图形大小和屏幕边界
// 绘制飞机图片
drawPlayer(posX, posY, ILI9341_WHITE);
updateScore();
// 清除先前的敌人图形
tft.fillRect(enemyX, enemyY, enemySize, enemySize, ILI9341_BLACK);
tft.setCursor(0, 0); // 设置光标位置
tft.print("Score: "); // 打印得分标签
tft.print(score); // 打印得分值
// 更新敌人图形的位置
updateEnemy();
// 绘制敌人图形
drawEnemy(enemyX, enemyY, ILI9341_RED);
// 移動敵人的子彈
moveEnemyBullets();
// 更新 prevX 和 prevY
prevX = posX;
prevY = posY;
// 检查碰撞
if (checkCollision(posX, posY, enemyX, enemyY, PLAYER_WIDTH, PLAYER_HEIGHT, enemySize)) {
// 处理碰撞情况
}
// 检查子弹是否击中敌人
for (int i = 0; i < bulletCount; i++) {
if (!bulletHit[i] && checkCollision(bulletX[i], bulletY[i], enemyX, enemyY, 2, PLAYER_HEIGHT, enemySize)) {
// 子弹击中了敌人
tft.fillRect(enemyX, enemyY, enemySize, enemySize, ILI9341_BLACK); // 清除敌人
bulletHit[i] = true; // 标记该子弹为已击中
score++; // 更新得分等游戏逻辑
enemyX = random(0, tft.width() - enemySize); // 重新生成敌人的X坐标
enemyY = -enemySize; // 将敌人重新放置在屏幕顶端
}
}
// 检查是否可以射击
if (micros() - lastShootTime > shootInterval && bulletCount < 50) {
// 射击子弹
shootBullet();
// 更新射击时间
lastShootTime = micros();
}
// 检查分数是否超过20
if (score > 3) {
displayEndScreen();
while (true) {
// 在这里什么也不做,只是等待结束画面显示
}
}
// 移动子弹
moveBullets();
delay(100); // 稍微延迟以避免屏幕闪烁
}
}
void updateScore() {
static int prevScore = -1; // 用于存储上一次更新的分数
// 检查分数是否发生变化
if (score != prevScore) {
// 清除先前的分数值
tft.fillRect(50, 0, 60, 20, ILI9341_BLACK);
tft.setCursor(0, 0); // 设置光标位置
tft.print("Score: "); // 打印得分标签
tft.print(score); // 打印得分值
prevScore = score; // 更新上一次的分数
}
}
void updateEnemy() {
// 根据敌人速度更新敌人的位置
enemyY += enemySpeed;
// 如果敌人超出屏幕底部,重新生成敌人并放置在屏幕顶部
if (enemyY > tft.height()) {
enemyY = -enemySize; // 从屏幕顶部重新开始
enemyX = random(0, tft.width() - enemySize); // 在屏幕内生成随机X坐标
}
// 检查是否可以射击子弹
if (millis() - lastEnemyBulletTime > ENEMY_BULLET_INTERVAL) {
shootEnemyBullet();
lastEnemyBulletTime = millis();
}
}
void shootEnemyBullet() {
// 找到一個可用的敵人子彈槽
for (int i = 0; i < MAX_ENEMY_BULLETS; i++) {
if (!enemyBulletActive[i]) {
// 找到了可用的子彈槽
enemyBulletX[i] = enemyX + enemySize / 2; // 子彈從敵人的中心發射
enemyBulletY[i] = enemyY + enemySize; // 子彈從敵人的底部發射
enemyBulletActive[i] = true;
enemyBulletCount++;
break; // 找到可用的子彈槽後退出迴圈
}
}
}
// 敵人移动子弹
void moveEnemyBullets() {
for (int i = 0; i < MAX_ENEMY_BULLETS; i++) {
if (enemyBulletActive[i]) {
// 清除上一个位置的子弹
tft.fillRect(enemyBulletX[i], enemyBulletY[i], 2, 5, ILI9341_BLACK);
// 移動敵人子彈
enemyBulletY[i] += ENEMY_BULLET_SPEED;
// 檢查是否擊中玩家
if (checkCollision(enemyBulletX[i], enemyBulletY[i], posX, posY, 2, PLAYER_HEIGHT, shapeSize)) {
// 如果擊中了玩家,執行相應的操作,這裡我們可以暫時將玩家的位置設置為畫面外來表示遊戲結束
posX = -shapeSize;
posY = -shapeSize;
drawPlayer(prevX, prevY, ILI9341_BLACK);
displayDefeatScreen();
while (true) {
// 在这里什么也不做,只是等待结束画面显示
}
// 這裡你可以添加其他的遊戲結束相關的操作,如顯示遊戲結束畫面、重置遊戲等
}
// 如果子彈超出畫面,將其標記為不活躍
if (enemyBulletY[i] > tft.height()) {
enemyBulletActive[i] = false;
enemyBulletCount--;
}
// 在屏幕上繪製敵人子彈
tft.fillRect(enemyBulletX[i], enemyBulletY[i], 2, 5, ILI9341_RED);
}
}
}
// 显示结束画面
void displayEndScreen() {
tft.fillScreen(ILI9341_BLACK); // 清空屏幕
tft.setTextSize(3); // 设置文字大小
tft.setCursor(50, 100); // 设置光标位置
tft.setTextColor(ILI9341_GREEN); // 设置文字颜色
tft.print("FIRST!"); // 显示游戏结束信息
// 在此处你可以添加其他的结束画面内容,如显示分数等
}
// 显示结束画面
void displayDefeatScreen() {
tft.fillScreen(ILI9341_BLACK); // 清空屏幕
tft.setTextSize(3); // 设置文字大小
tft.setCursor(60, 100); // 设置光标位置
tft.setTextColor(ILI9341_RED); // 设置文字颜色
tft.print("Failed"); // 显示游戏结束信息
tft.setTextSize(3); // 设置文字大小
tft.setCursor(50, 150); // 设置光标位置
tft.setTextColor(ILI9341_WHITE); // 设置文字颜色
tft.print("Score: "); // 打印得分标签
tft.print(score); // 打印得分值
// 在此处你可以添加其他的结束画面内容,如显示分数等
}
// 绘制玩家图形
void drawPlayer(int x, int y, uint16_t color) {
// 横杠
tft.fillRect(x, y, PLAYER_WIDTH, 2 * shapeSize, color);
// 左竖杠
tft.fillRect(x - shapeSize, y - (PLAYER_HEIGHT / 2) + (shapeSize / 2), shapeSize, PLAYER_HEIGHT, color);
// 右豎杠
tft.fillRect(PLAYER_WIDTH + x, y - (PLAYER_HEIGHT / 2) + (shapeSize / 2), shapeSize, PLAYER_HEIGHT, color);
}
// 绘制敌人图形
void drawEnemy(int x, int y, uint16_t color) {
tft.drawRect(x, y, enemySize, enemySize, color);
}
// 检查碰撞
bool checkCollision(int playerX, int playerY, int enemyX, int enemyY, int playerWidth, int playerHeight, int enemySize) {
// 计算玩家图形的边界框
int playerLeft = playerX - shapeSize;
int playerRight = playerX + PLAYER_WIDTH + shapeSize;
int playerTop = playerY - (PLAYER_HEIGHT / 2) + (shapeSize / 2);
int playerBottom = playerY + (PLAYER_HEIGHT / 2) + (shapeSize / 2);
// 计算敌人图形的边界框
int enemyLeft = enemyX;
int enemyRight = enemyX + enemySize;
int enemyTop = enemyY;
int enemyBottom = enemyY + enemySize;
// 检查两个矩形是否相交,如果相交则返回 true,否则返回 false
if (playerLeft < enemyRight &&
playerRight > enemyLeft &&
playerTop < enemyBottom &&
playerBottom > enemyTop) {
return true;
}
return false;
}
// 射击子弹的函数
void shootBullet() {
if (bulletCount < 50) {
// 子弹从玩家图形的上方中心点生成
int bulletPosX = posX + shapeSize / 2;
int bulletPosY = posY + 5; // 微调位置,避免与玩家图形重叠
// 如果玩家图形靠近屏幕边界,调整子弹的生成位置
if (bulletPosX < 0) {
bulletPosX = 0; // 玩家靠近屏幕左边界
} else if (bulletPosX > tft.width() - 2) {
bulletPosX = tft.width() - 2; // 玩家靠近屏幕右边界
}
if (bulletPosY < 0) {
bulletPosY = 0; // 玩家靠近屏幕上边界
} else if (bulletPosY > tft.height() - 5) {
bulletPosY = tft.height() - 5; // 玩家靠近屏幕下边界
}
bulletX[bulletCount] = bulletPosX;
bulletY[bulletCount] = bulletPosY;
bulletCount++;
}
}
// 玩家移动子弹
void moveBullets() {
for (int i = 0; i < bulletCount; i++) {
// 如果子弹未超出屏幕,则移动子弹并绘制
if (bulletY[i] >= 0 && bulletY[i] < tft.height()) {
// 清除子弹的上一个位置
tft.fillRect(bulletX[i], bulletY[i], 2, 5, ILI9341_BLACK);
// 检查子弹是否击中敌人
bool hitEnemy = checkCollision(bulletX[i], bulletY[i], enemyX, enemyY, 2, shapeSize, enemySize);
// 如果子弹击中了敌人,则清除敌人,并移除子弹
if (hitEnemy) {
tft.fillRect(enemyX, enemyY, enemySize, enemySize, ILI9341_BLACK); // 清除敌人
bulletHit[i] = true; // 标记该子弹为已击中
score++; // 更新得分等游戏逻辑
enemyX = random(0, tft.width() - enemySize); // 重新生成敌人的X坐标
enemyY = -enemySize; // 将敌人重新放置在屏幕顶端
} else {
bulletY[i] -= bulletSpeed; // 子弹向上移动
tft.fillRect(bulletX[i], bulletY[i], 2, 5, ILI9341_WHITE); // 绘制新的子弹
}
} else { // 如果子弹超出屏幕,则移除子弹
bulletX[i] = bulletX[bulletCount - 1];
bulletY[i] = bulletY[bulletCount - 1];
bulletCount--;
}
}
}
void drawMainMenu() {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(70, 120);
tft.print("START");
tft.setCursor(70, 200);
tft.print("TARN OFF");
GameState = 1;
drawArrow(arrowFX, arrowFY);
}
void drawDifficultySelectionMenu() {
// 绘制选择模式界面
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(90, 100);
tft.print("EASY");
tft.setCursor(90, 150);
tft.print("NORMAL");
tft.setCursor(90, 200);
tft.print("HARD");
tft.setCursor(90, 250);
tft.print("BACK");
drawArrow(arrowX, arrowY);
}
void back() {
GameState = 3; // 进入游戏进行状态
startGame(Difficulty); // 开始游戏
}
void handleJoystick(int &arrowY, int &prevJoyY, int arrowYchange, int arrowYtop, int arrowYlow) {
int joyY = analogRead(JOY_Y);
if (joyY != prevJoyY) {
Serial.print(joyY);
if (joyY < 1700) {
tft.fillRect(arrowX - arrowSize - 6, arrowY - (arrowSize / 2) - 6, arrowSize * 2 + 12, arrowSize * 2 + 12, ILI9341_BLACK);
arrowY += arrowYchange;
if (arrowY > arrowYtop) {
arrowY = arrowYlow;
}
drawArrow(arrowX, arrowY);
} else if (joyY > 2200) {
tft.fillRect(arrowX - arrowSize - 6, arrowY - (arrowSize / 2) - 6, arrowSize * 2 + 12, arrowSize * 2 + 12, ILI9341_BLACK);
arrowY -= arrowYchange;
if (arrowY < arrowYlow) {
arrowY = arrowYtop;
}
drawArrow(arrowX, arrowY);
}
prevJoyY = joyY;
}
}FPS: 0
Power: 0.00W
Power: 0.00W
FPS: 0
Power: 0.00W
Power: 0.00W