22222222222444
Published

Tutorial on Developing a Shooting Game Using Arduino and Wio

Build a pixel-art vertical scrolling shooter (STG) from scratch using modern microcontroller platforms like Wio Terminal and Arduino

BeginnerProtip16
Tutorial on Developing a Shooting Game Using Arduino and Wio

Things used in this project

Hardware components

Wio Terminal
Seeed Studio Wio Terminal
×1
USB Cable, USB Type C Plug
USB Cable, USB Type C Plug
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

Developing a Shooting Game for Fighter Jets Using Arduino and Wio Terminal

Arduino
Enter this code into Arduino and run it in the Arduino and Wio Terminal environment.
#include <TFT_eSPI.h>
#include "LIS3DHTR.h"

TFT_eSPI tft;
LIS3DHTR<TwoWire> lis;

// 按钮定义
#define LEFT_BUTTON WIO_KEY_B
#define RIGHT_BUTTON WIO_KEY_A
#define PAUSE_BUTTON WIO_KEY_C
#define SELECT_BUTTON WIO_5S_UP    // 使用5向开关的上键作为选择键
#define BACK_BUTTON WIO_5S_DOWN    // 使用5向开关的下键作为返回键

// 游戏常量
const int SCREEN_WIDTH = 320;
const int SCREEN_HEIGHT = 240;
const int PLAYER_SIZE = 20;
const int BULLET_SIZE = 4;
const int ENEMY_SIZE = 16;
const int MAX_ENEMIES = 20;
const int MAX_EXPLOSIONS = 5;
const int BASE_PLAYER_SPEED = 5;
const int AUTO_FIRE_DELAY = 500;
const int NUM_LEVELS = 4;

// 屏幕中心坐标
const int CENTER_X = SCREEN_WIDTH / 2;
const int CENTER_Y = SCREEN_HEIGHT / 2;

// 关卡分数阈值
const int LEVEL_THRESHOLDS[] = {300, 500, 700, 1000};

// 颜色定义
#define BACKGROUND_COLOR 0x0000  // 更深的黑色
#define PLAYER_COLOR 0x07FF      // 更亮的青色
#define BULLET_COLOR 0xFFE0      // 更亮的黄色
#define LASER_COLOR 0x001F       // 更亮的蓝色
#define SHOTGUN_COLOR 0xF800     // 更亮的红色
#define ENEMY1_COLOR 0x07E0      // 更亮的绿色
#define ENEMY2_COLOR 0xFFE0      // 更亮的黄色
#define ENEMY3_COLOR 0xFD20      // 更亮的橙色
#define ENEMY4_COLOR 0x781F      // 更亮的紫色
#define ENEMY5_COLOR 0xF81F      // 更亮的洋红色
#define BOSS_COLOR 0xF800        // 更亮的红色
#define SHIELD_COLOR 0x07FF      // 更亮的青色
#define POWERUP_WEAPON_COLOR 0x001F  // 更亮的蓝色
#define POWERUP_SHIELD_COLOR 0x07FF  // 更亮的青色
#define POWERUP_SPEED_COLOR 0x07E0   // 更亮的绿色
#define POWERUP_SHIP_COLOR 0xFFE0    // 更亮的黄色
#define EXPLOSION_COLOR 0xFD20       // 更亮的橙色
#define HEALTH_BAR_COLOR 0x07E0      // 更亮的绿色
#define HEALTH_BAR_BG_COLOR 0xD000   // 暗红色
#define MENU_HIGHLIGHT_COLOR 0xFFE0  // 更亮的黄色
#define MENU_NORMAL_COLOR 0xFFFF     // 纯白色
#define STAR_COLOR 0x8410           // 灰色星星

// 游戏模式
#define MODE_NORMAL 0
#define MODE_HARD 1
int gameMode = MODE_NORMAL;

// 游戏变量
int playerX = CENTER_X;
int playerY = SCREEN_HEIGHT - 30;
int score = 0;
int levelScore = 0;
int lives = 3;
int playerHealth = 100;
int maxPlayerHealth = 100;
int gameState = -1; // -1=模式选择, 0=开始界面, 1=游戏中, 2=游戏结束, 3=暂停, 4=关卡过渡
int currentLevel = 0;
bool bossSpawned = false;
bool bossDefeated = false;
bool bossWarning = false;
unsigned long bossWarningTime = 0;
unsigned long lastAutoFireTime = 0;
unsigned long levelTransitionTime = 0;
bool specialActive = false;
int specialTimer = 0;
int playerUpgradeLevel = 0;
int bulletUpgradeLevel = 0;
int playerPower = 0;
int powerTimer = 0;
int playerSpeed = BASE_PLAYER_SPEED;
int speedBoostTimer = 0;

// 背景星星
struct Star {
  int x, y;
  int speed;
  int size;
};
const int NUM_STARS = 50;
Star stars[NUM_STARS];

// 结构体定义
struct Bullet {
  int x, y;
  int type;
  int speed;
  Bullet* next;
};

struct Enemy {
  int x, y;
  bool active;
  int type;
  int health;
  int maxHealth;
  int speed;
  int movePattern;
  unsigned long lastShot;
  int moveDirection;
  int bossLevel;
  int enemyLevel;
};

struct PowerUp {
  int x, y;
  bool active;
  int type;
};

struct Explosion {
  int x, y;
  bool active;
  int frame;
  unsigned long startTime;
};

// 全局对象
Bullet* bulletList = NULL;
Enemy enemies[MAX_ENEMIES];
PowerUp powerUps[5];
Explosion explosions[MAX_EXPLOSIONS];

// 函数前置声明
void initGame();
void initStars();
void updateStars();
void drawStars();
void showModeSelect();
void showStartScreen();
void updateGame();
void handleInput();
void autoFire();
void fireBullet();
void updateBullets();
void updateEnemies();
void spawnEnemy();
void updatePowerUps();
void spawnPowerUp(int x, int y, int type = -1);
void checkCollisions();
void drawGame();
void drawPlayer();
void drawUI();
void showGameOver();
void showPauseScreen();
void showLevelTransition();
void activateSpecial();
void addExplosion(int x, int y);
void updateExplosions();
void drawExplosions();
void addBulletToList(int x, int y, int type, int speed);
void removeBulletFromList(Bullet* bulletToRemove);
void clearAllBullets();
void checkLevelProgress();
void upgradePlayer();
void upgradeBullets();
void spawnBoss();
void showBossWarning();
void updateBoss(int index);
void drawBoss(int index);
void drawEnemy(int index);
uint16_t getBulletColor(int type);
uint16_t getEnemyColor(int type, int level);
uint16_t getPowerUpColor(int type);
String getPowerUpSymbol(int type);
void increaseFireRate();
void increaseSpeed();
void drawHealthBar();

void setup() {
  Serial.begin(115200);
  
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(BACKGROUND_COLOR);
  
  pinMode(LEFT_BUTTON, INPUT_PULLUP);
  pinMode(RIGHT_BUTTON, INPUT_PULLUP);
  pinMode(PAUSE_BUTTON, INPUT_PULLUP);
  pinMode(SELECT_BUTTON, INPUT_PULLUP);
  pinMode(BACK_BUTTON, INPUT_PULLUP);
  
  initStars();
  initGame();
  showModeSelect();
}

void loop() {
  switch(gameState) {
    case -1: // 模式选择
      if(digitalRead(SELECT_BUTTON) == LOW) {
        gameState = 0;
        showStartScreen();
        delay(300);
      }
      if(digitalRead(LEFT_BUTTON) == LOW || digitalRead(RIGHT_BUTTON) == LOW) {
        gameMode = !gameMode;
        showModeSelect();
        delay(300);
      }
      break;
      
    case 0: // 开始界面
      if(digitalRead(PAUSE_BUTTON) == LOW) {
        gameState = 1;
        tft.fillScreen(BACKGROUND_COLOR);
        delay(300);
      }
      break;
      
    case 1: // 游戏中
      updateGame();
      break;
      
    case 2: // 游戏结束
      if(digitalRead(PAUSE_BUTTON) == LOW) {
        initGame();
        gameState = -1;
        showModeSelect();
        delay(300);
      }
      break;
      
    case 3: // 暂停
      if(digitalRead(PAUSE_BUTTON) == LOW) {
        gameState = 1;
        delay(300);
      }
      break;
      
    case 4: // 关卡过渡
      if(millis() - levelTransitionTime > 3000) {
        gameState = 1;
        bossSpawned = false;
        bossDefeated = false;
        bossWarning = false;
        levelScore = 0;
        currentLevel++;
        if(currentLevel >= NUM_LEVELS) {
          currentLevel = 0;
          score = 0;
          initGame();
          gameState = -1;
          showModeSelect();
        }
      }
      showLevelTransition();
      break;
  }
  delay(16);
}

void initStars() {
  for(int i = 0; i < NUM_STARS; i++) {
    stars[i].x = random(SCREEN_WIDTH);
    stars[i].y = random(SCREEN_HEIGHT);
    stars[i].speed = random(1, 4);
    stars[i].size = random(1, 3);
  }
}

void updateStars() {
  for(int i = 0; i < NUM_STARS; i++) {
    stars[i].y += stars[i].speed;
    if(stars[i].y > SCREEN_HEIGHT) {
      stars[i].y = 0;
      stars[i].x = random(SCREEN_WIDTH);
    }
  }
}

void drawStars() {
  for(int i = 0; i < NUM_STARS; i++) {
    tft.fillCircle(stars[i].x, stars[i].y, stars[i].size, STAR_COLOR);
  }
}

void initGame() {
  playerX = CENTER_X;
  score = 0;
  levelScore = 0;
  lives = 3;
  playerHealth = maxPlayerHealth;
  playerPower = 0;
  specialActive = false;
  specialTimer = 0;
  lastAutoFireTime = 0;
  currentLevel = 0;
  bossSpawned = false;
  bossDefeated = false;
  bossWarning = false;
  playerUpgradeLevel = 0;
  bulletUpgradeLevel = 0;
  playerSpeed = BASE_PLAYER_SPEED;
  speedBoostTimer = 0;
  
  clearAllBullets();
  
  for(int i = 0; i < MAX_ENEMIES; i++) {
    enemies[i].active = false;
  }
  
  for(int i = 0; i < 5; i++) {
    powerUps[i].active = false;
  }
  
  for(int i = 0; i < MAX_EXPLOSIONS; i++) {
    explosions[i].active = false;
  }
}

void showModeSelect() {
  tft.fillScreen(BACKGROUND_COLOR);
  tft.setTextSize(2);
  tft.setTextColor(MENU_HIGHLIGHT_COLOR);
  tft.setCursor(CENTER_X - 70, 50);
  tft.print("选择游戏模式");
  
  tft.setTextSize(2);
  if(gameMode == MODE_NORMAL) {
    tft.setTextColor(MENU_HIGHLIGHT_COLOR);
    tft.setCursor(CENTER_X - 40, 120);
    tft.print("普通模式");
    tft.setTextColor(MENU_NORMAL_COLOR);
    tft.setCursor(CENTER_X - 40, 160);
    tft.print("困难模式");
  } else {
    tft.setTextColor(MENU_NORMAL_COLOR);
    tft.setCursor(CENTER_X - 40, 120);
    tft.print("普通模式");
    tft.setTextColor(MENU_HIGHLIGHT_COLOR);
    tft.setCursor(CENTER_X - 40, 160);
    tft.print("困难模式");
  }
  
  tft.setTextSize(1);
  tft.setTextColor(MENU_NORMAL_COLOR);
  tft.setCursor(CENTER_X - 100, 200);
  tft.print("左右键选择 上键确认");
}

void updateGame() {
  updateStars();
  handleInput();
  autoFire();
  updateBullets();
  updateEnemies();
  updatePowerUps();
  updateExplosions();
  checkCollisions();
  checkLevelProgress();
  drawGame();
  
  if(lives <= 0 || playerHealth <= 0) {
    gameState = 2;
    showGameOver();
  }
  
  if(specialActive && specialTimer > 0) {
    specialTimer--;
    if(specialTimer == 0) {
      specialActive = false;
    }
  }
  
  if(speedBoostTimer > 0) {
    speedBoostTimer--;
    if(speedBoostTimer == 0) {
      playerSpeed = BASE_PLAYER_SPEED;
    }
  }
  
  if(bossWarning && millis() - bossWarningTime > 3000) {
    bossWarning = false;
    spawnBoss();
  }
}

void handleInput() {
  if(digitalRead(LEFT_BUTTON) == LOW) {
    playerX -= playerSpeed;
    playerX = max(playerX, PLAYER_SIZE/2 + (playerUpgradeLevel * 5));
  }
  
  if(digitalRead(RIGHT_BUTTON) == LOW) {
    playerX += playerSpeed;
    playerX = min(playerX, SCREEN_WIDTH - PLAYER_SIZE/2 - (playerUpgradeLevel * 5));
  }
  
  if(digitalRead(PAUSE_BUTTON) == LOW) {
    if(gameState == 1) {
      gameState = 3;
      showPauseScreen();
    }
    delay(300);
  }
}

void autoFire() {
  if(gameState == 1 && millis() - lastAutoFireTime > AUTO_FIRE_DELAY) {
    fireBullet();
    lastAutoFireTime = millis();
  }
}

void fireBullet() {
  int bulletType = playerPower == 3 ? 2 : (playerPower == 1 ? 1 : 0);
  int bulletSpeed = bulletType == 0 ? 8 : (bulletType == 1 ? 12 : 6);
  
  addBulletToList(playerX, playerY - PLAYER_SIZE/2, bulletType, bulletSpeed);
  
  if(bulletUpgradeLevel >= 1) {
    addBulletToList(playerX - 8, playerY - PLAYER_SIZE/2, bulletType, bulletSpeed);
    addBulletToList(playerX + 8, playerY - PLAYER_SIZE/2, bulletType, bulletSpeed);
  }
  
  if(bulletUpgradeLevel >= 2) {
    addBulletToList(playerX - 16, playerY - PLAYER_SIZE/2, bulletType, bulletSpeed);
    addBulletToList(playerX + 16, playerY - PLAYER_SIZE/2, bulletType, bulletSpeed);
  }
  
  if(playerPower == 3) {
    addBulletToList(playerX - 8, playerY - PLAYER_SIZE/2, 2, 6);
    addBulletToList(playerX + 8, playerY - PLAYER_SIZE/2, 2, 6);
  }
}

void addBulletToList(int x, int y, int type, int speed) {
  Bullet* newBullet = new Bullet;
  newBullet->x = x;
  newBullet->y = y;
  newBullet->type = type;
  newBullet->speed = speed;
  newBullet->next = NULL;
  
  if(bulletList == NULL) {
    bulletList = newBullet;
  } else {
    newBullet->next = bulletList;
    bulletList = newBullet;
  }
}

void removeBulletFromList(Bullet* bulletToRemove) {
  if(bulletList == NULL) return;
  
  if(bulletList == bulletToRemove) {
    Bullet* temp = bulletList;
    bulletList = bulletList->next;
    delete temp;
    return;
  }
  
  Bullet* current = bulletList;
  while(current->next != NULL) {
    if(current->next == bulletToRemove) {
      Bullet* temp = current->next;
      current->next = current->next->next;
      delete temp;
      return;
    }
    current = current->next;
  }
}

void clearAllBullets() {
  Bullet* current = bulletList;
  while(current != NULL) {
    Bullet* next = current->next;
    delete current;
    current = next;
  }
  bulletList = NULL;
}

void updateBullets() {
  Bullet* current = bulletList;
  while(current != NULL) {
    current->y -= current->speed;
    
    if(current->y < 0) {
      Bullet* toRemove = current;
      current = current->next;
      removeBulletFromList(toRemove);
    } else {
      current = current->next;
    }
  }
}

void updateEnemies() {
  static unsigned long lastSpawnTime = 0;
  
  int spawnDelay = 1000 - min(score/10, 800) - (currentLevel * 100);
  spawnDelay = max(spawnDelay, 200);
  
  // 困难模式敌人更多
  if(gameMode == MODE_HARD) {
    spawnDelay = spawnDelay * 2 / 3;
  }
  
  if(bossSpawned) {
    spawnDelay = spawnDelay * 3 / 2;
  }
  
  if(millis() - lastSpawnTime > spawnDelay) {
    spawnEnemy();
    lastSpawnTime = millis();
  }
  
  for(int i = 0; i < MAX_ENEMIES; i++) {
    if(enemies[i].active) {
      if(enemies[i].type == 3) {
        updateBoss(i);
      } else {
        enemies[i].y += enemies[i].speed;
        
        if(enemies[i].movePattern == 1) {
          enemies[i].x += sin(millis()/500.0 + i) * 2;
        } else if(enemies[i].movePattern == 2) {
          enemies[i].x += cos(millis()/300.0 + i) * 3;
        }
        
        enemies[i].x = constrain(enemies[i].x, ENEMY_SIZE/2, SCREEN_WIDTH - ENEMY_SIZE/2);
        
        if(enemies[i].y > SCREEN_HEIGHT) {
          enemies[i].active = false;
          if(enemies[i].type != 3) {
            // 敌人到达底部,玩家受到伤害
            playerHealth -= 10;
            if(playerHealth < 0) playerHealth = 0;
            addExplosion(enemies[i].x, enemies[i].y);
          }
        }
        
        if(enemies[i].type >= 1 && millis() - enemies[i].lastShot > 2000 && random(100) < (5 + currentLevel * 2)) {
          // 困难模式敌人射击更频繁
          int shotChance = (gameMode == MODE_HARD) ? (10 + currentLevel * 3) : (5 + currentLevel * 2);
          if(random(100) < shotChance) {
            addBulletToList(enemies[i].x, enemies[i].y + ENEMY_SIZE/2, 0, -4 - currentLevel);
            enemies[i].lastShot = millis();
          }
        }
      }
    }
  }
}

void updateBoss(int index) {
  Enemy* boss = &enemies[index];
  int bossLevel = boss->bossLevel;
  
  boss->x += boss->moveDirection * boss->speed;
  
  if(boss->x <= ENEMY_SIZE || boss->x >= SCREEN_WIDTH - ENEMY_SIZE) {
    boss->moveDirection *= -1;
  }
  
  int attackDelay = 1000 - (bossLevel * 200);
  attackDelay = max(attackDelay, 300);
  
  // 困难模式BOSS攻击更频繁
  if(gameMode == MODE_HARD) {
    attackDelay = attackDelay * 2 / 3;
  }
  
  if(millis() - boss->lastShot > attackDelay && random(100) < (20 + bossLevel * 10)) {
    addBulletToList(boss->x, boss->y + ENEMY_SIZE, 0, -6 - bossLevel);
    
    if(bossLevel >= 1) {
      addBulletToList(boss->x - 10, boss->y + ENEMY_SIZE, 0, -5 - bossLevel);
      addBulletToList(boss->x + 10, boss->y + ENEMY_SIZE, 0, -5 - bossLevel);
    }
    
    if(bossLevel >= 2) {
      addBulletToList(boss->x - 20, boss->y + ENEMY_SIZE, 0, -4 - bossLevel);
      addBulletToList(boss->x + 20, boss->y + ENEMY_SIZE, 0, -4 - bossLevel);
    }
    
    if(bossLevel >= 3) {
      for(int i = 0; i < 5; i++) {
        addBulletToList(boss->x - 20 + i*10, boss->y + ENEMY_SIZE, 2, -4 - bossLevel);
      }
    }
    
    boss->lastShot = millis();
  }
}

void spawnEnemy() {
  if(!bossSpawned && !bossWarning && levelScore >= LEVEL_THRESHOLDS[currentLevel]) {
    showBossWarning();
    return;
  }
  
  for(int i = 0; i < MAX_ENEMIES; i++) {
    if(!enemies[i].active) {
      enemies[i].x = random(ENEMY_SIZE, SCREEN_WIDTH - ENEMY_SIZE);
      enemies[i].y = -ENEMY_SIZE;
      enemies[i].active = true;
      enemies[i].enemyLevel = currentLevel;
      
      int enemyType = random(100);
      
      if(enemyType < 60 - currentLevel * 10) {
        enemies[i].type = 0;
      } else if(enemyType < 85 - currentLevel * 5) {
        enemies[i].type = 1;
      } else {
        enemies[i].type = 2;
      }
      
      // 困难模式敌人更强
      int healthBonus = currentLevel * 2;
      int speedBonus = currentLevel / 2;
      
      if(gameMode == MODE_HARD) {
        healthBonus += 2;
        speedBonus += 1;
      }
      
      switch(enemies[i].type) {
        case 0:
          enemies[i].health = 1 + healthBonus;
          enemies[i].maxHealth = enemies[i].health;
          enemies[i].speed = 1 + speedBonus;
          enemies[i].movePattern = 0;
          break;
        case 1:
          enemies[i].health = 2 + healthBonus;
          enemies[i].maxHealth = enemies[i].health;
          enemies[i].speed = 1 + speedBonus;
          enemies[i].movePattern = 1;
          break;
        case 2:
          enemies[i].health = 3 + healthBonus;
          enemies[i].maxHealth = enemies[i].health;
          enemies[i].speed = 1 + speedBonus;
          enemies[i].movePattern = 2;
          break;
      }
      
      enemies[i].lastShot = millis();
      break;
    }
  }
}

void showBossWarning() {
  bossWarning = true;
  bossWarningTime = millis();
}

void spawnBoss() {
  for(int i = 0; i < MAX_ENEMIES; i++) {
    if(!enemies[i].active) {
      enemies[i].x = CENTER_X;
      enemies[i].y = ENEMY_SIZE * 2;
      enemies[i].active = true;
      enemies[i].type = 3;
      
      int baseHealth = 5;
      enemies[i].health = baseHealth * 100 * (currentLevel + 1);
      
      // 困难模式BOSS更强
      if(gameMode == MODE_HARD) {
        enemies[i].health = enemies[i].health * 3 / 2;
      }
      
      enemies[i].maxHealth = enemies[i].health;
      
      enemies[i].speed = 2 + currentLevel;
      enemies[i].movePattern = 3;
      enemies[i].lastShot = millis();
      enemies[i].moveDirection = 1;
      enemies[i].bossLevel = currentLevel;
      
      bossSpawned = true;
      break;
    }
  }
}

void updatePowerUps() {
  if(playerPower > 0 && powerTimer > 0) {
    powerTimer--;
    if(powerTimer == 0) {
      playerPower = 0;
    }
  }
  
  if(speedBoostTimer > 0) {
    speedBoostTimer--;
    if(speedBoostTimer == 0) {
      playerSpeed = BASE_PLAYER_SPEED;
    }
  }
  
  for(int i = 0; i < 5; i++) {
    if(powerUps[i].active) {
      powerUps[i].y += 2;
      
      if(powerUps[i].y > SCREEN_HEIGHT) {
        powerUps[i].active = false;
      }
    }
  }
}

void checkCollisions() {
  Bullet* current = bulletList;
  while(current != NULL) {
    if(current->speed > 0) {
      for(int j = 0; j < MAX_ENEMIES; j++) {
        if(enemies[j].active) {
          int hitSize = enemies[j].type == 3 ? ENEMY_SIZE * 2 : ENEMY_SIZE;
          
          if(abs(current->x - enemies[j].x) < hitSize/2 && 
             abs(current->y - enemies[j].y) < hitSize/2) {
            
            Bullet* toRemove = current;
            current = current->next;
            removeBulletFromList(toRemove);
            
            enemies[j].health--;
            
            if(enemies[j].health <= 0) {
              int points = 0;
              switch(enemies[j].type) {
                case 0: points = 10; break;
                case 1: points = 30; break;
                case 2: points = 50; break;
                case 3: points = 200 + (currentLevel * 100); break;
              }
              score += points;
              levelScore += points;
              
              addExplosion(enemies[j].x, enemies[j].y);
              
              if(enemies[j].type == 3) {
                bossDefeated = true;
                spawnPowerUp(enemies[j].x, enemies[j].y, 3); // S: 升级战机
              } else {
                if(random(100) < 50) {
                  int powerType = random(4); // 0-3 四种奖励
                  spawnPowerUp(enemies[j].x, enemies[j].y, powerType);
                }
              }
              
              enemies[j].active = false;
            }
            break;
          }
        }
      }
      if(current != NULL) current = current->next;
    } else {
      current = current->next;
    }
  }
  
  current = bulletList;
  while(current != NULL) {
    if(current->speed < 0) {
      int playerHitSize = PLAYER_SIZE + (playerUpgradeLevel * 5);
      
      if(abs(playerX - current->x) < playerHitSize/2 && 
         abs(playerY - current->y) < playerHitSize/2) {
        
        Bullet* toRemove = current;
        current = current->next;
        removeBulletFromList(toRemove);
        
        if(playerPower != 2) { // 如果没有护盾
          playerHealth -= 10;
          if(playerHealth < 0) playerHealth = 0;
          addExplosion(playerX, playerY);
          
          if(playerHealth <= 0) {
            lives--;
            playerHealth = maxPlayerHealth;
          }
        }
        break;
      }
    }
    if(current != NULL) current = current->next;
  }
  
  for(int i = 0; i < MAX_ENEMIES; i++) {
    if(enemies[i].active) {
      int enemyHitSize = enemies[i].type == 3 ? ENEMY_SIZE * 2 : ENEMY_SIZE;
      int playerHitSize = PLAYER_SIZE + (playerUpgradeLevel * 5);
      
      if(abs(playerX - enemies[i].x) < (playerHitSize + enemyHitSize)/2 && 
         abs(playerY - enemies[i].y) < (playerHitSize + enemyHitSize)/2) {
        
        enemies[i].active = false;
        if(playerPower != 2) { // 如果没有护盾
          playerHealth -= 20;
          if(playerHealth < 0) playerHealth = 0;
          addExplosion(playerX, playerY);
          addExplosion(enemies[i].x, enemies[i].y);
          
          if(playerHealth <= 0) {
            lives--;
            playerHealth = maxPlayerHealth;
          }
        }
        break;
      }
    }
  }
  
  for(int i = 0; i < 5; i++) {
    if(powerUps[i].active) {
      int playerHitSize = PLAYER_SIZE + (playerUpgradeLevel * 5);
      
      if(abs(playerX - powerUps[i].x) < playerHitSize/2 && 
         abs(playerY - powerUps[i].y) < playerHitSize/2) {
        
        // 根据道具类型应用效果
        switch(powerUps[i].type) {
          case 0: // A: 增加发射弹数
            increaseFireRate();
            break;
          case 1: // B: 增加防护盾
            playerPower = 2;
            powerTimer = 300;
            break;
          case 2: // C: 增加战机移速
            increaseSpeed();
            break;
          case 3: // S: 升级战机
            upgradePlayer();
            break;
        }
        
        powerUps[i].active = false;
      }
    }
  }
}

void spawnPowerUp(int x, int y, int type) {
  for(int i = 0; i < 5; i++) {
    if(!powerUps[i].active) {
      powerUps[i].x = x;
      powerUps[i].y = y;
      powerUps[i].active = true;
      powerUps[i].type = (type == -1) ? random(4) : type;
      break;
    }
  }
}

void addExplosion(int x, int y) {
  for(int i = 0; i < MAX_EXPLOSIONS; i++) {
    if(!explosions[i].active) {
      explosions[i].x = x;
      explosions[i].y = y;
      explosions[i].active = true;
      explosions[i].frame = 0;
      explosions[i].startTime = millis();
      break;
    }
  }
}

void updateExplosions() {
  for(int i = 0; i < MAX_EXPLOSIONS; i++) {
    if(explosions[i].active) {
      if(millis() - explosions[i].startTime > 500) {
        explosions[i].active = false;
      } else {
        explosions[i].frame = (millis() - explosions[i].startTime) / 100;
      }
    }
  }
}

void checkLevelProgress() {
  if(currentLevel < NUM_LEVELS && levelScore >= LEVEL_THRESHOLDS[currentLevel] && bossDefeated) {
    gameState = 4;
    levelTransitionTime = millis();
  }
}

void upgradePlayer() {
  if(playerUpgradeLevel < 2) {
    playerUpgradeLevel++;
    maxPlayerHealth += 20;
    playerHealth = maxPlayerHealth;
  }
}

void upgradeBullets() {
  if(bulletUpgradeLevel < 2) {
    bulletUpgradeLevel++;
  }
}

void increaseFireRate() {
  // 增加发射速率
  if(AUTO_FIRE_DELAY > 200) {
    lastAutoFireTime = millis() - (AUTO_FIRE_DELAY - 100);
  }
}

void increaseSpeed() {
  playerSpeed = BASE_PLAYER_SPEED * 2;
  speedBoostTimer = 300;
}

uint16_t getBulletColor(int type) {
  switch(type) {
    case 0: return BULLET_COLOR;
    case 1: return LASER_COLOR;
    case 2: return SHOTGUN_COLOR;
    default: return TFT_WHITE;
  }
}

uint16_t getEnemyColor(int type, int level) {
  switch(type) {
    case 0:
      if(level == 0) return ENEMY1_COLOR;
      else if(level == 1) return 0xAFE5; // 更亮的蓝绿色
      else if(level == 2) return 0x9D2B; // 更亮的橄榄色
      else return 0x2D0A; // 更亮的深绿色
    case 1:
      if(level == 0) return ENEMY2_COLOR;
      else if(level == 1) return 0xFFE6; // 更亮的黄色
      else if(level == 2) return 0xFD40; // 更亮的橙色
      else return 0xFD40; // 更亮的橙色
    case 2:
      if(level == 0) return ENEMY3_COLOR;
      else if(level == 1) return 0x981F; // 更亮的紫色
      else if(level == 2) return 0xF81F; // 更亮的洋红色
      else return 0x8800; // 更亮的栗色
    default: return TFT_WHITE;
  }
}

uint16_t getPowerUpColor(int type) {
  switch(type) {
    case 0: return POWERUP_WEAPON_COLOR;    // A: 蓝色
    case 1: return POWERUP_SHIELD_COLOR;    // B: 青色
    case 2: return POWERUP_SPEED_COLOR;     // C: 绿色
    case 3: return POWERUP_SHIP_COLOR;      // S: 黄色
    default: return TFT_WHITE;
  }
}

String getPowerUpSymbol(int type) {
  switch(type) {
    case 0: return "A";
    case 1: return "B";
    case 2: return "C";
    case 3: return "S";
    default: return "?";
  }
}

void drawGame() {
  tft.fillScreen(BACKGROUND_COLOR);
  drawStars();
  
  Bullet* current = bulletList;
  while(current != NULL) {
    uint16_t color = getBulletColor(current->type);
    if(current->speed > 0) {
      if(current->type == 0) {
        // 普通子弹 - 更精致的绘制
        tft.fillCircle(current->x, current->y, BULLET_SIZE, color);
        tft.fillCircle(current->x, current->y, BULLET_SIZE-1, TFT_WHITE);
      } else if(current->type == 1) {
        // 激光 - 更精致的绘制
        tft.fillRect(current->x - 2, current->y - 10, 4, 20, color);
        tft.drawFastVLine(current->x, current->y - 12, 24, TFT_WHITE);
      } else {
        // 霰弹 - 更精致的绘制
        tft.fillCircle(current->x, current->y, BULLET_SIZE + 2, color);
        tft.fillCircle(current->x, current->y, BULLET_SIZE, TFT_WHITE);
      }
    } else {
      // 敌人子弹
...

This file has been truncated, please download it to see its full contents.

Credits

22222222222444
1 project • 0 followers

Comments