You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino 16x2 LCD无限跑酷游戏Enemy实例自删除问题求助

Arduino 16x2 LCD跑酷游戏敌人销毁问题

我在Arduino平台开发一款基于16x2 LCD的无限跑酷游戏,敌人会向左移动,原本希望Enemy类实例在x位置到达0时自行销毁,但用delete(this)后没成功。现在程序运行时,敌人xPos变为负值后不会被删除,反而在屏幕中间随机位置重新出现,还引发屏幕故障。

问题根源

  • 栈对象不能用delete销毁:你定义的Enemy e(15, 1)是全局栈分配对象,delete仅适用于堆上用new创建的对象。手动销毁栈对象会触发未定义行为,导致内存混乱,出现敌人乱跳的情况。
  • 销毁后仍调用方法:就算销毁成功,loop里还会持续调用e.move()和e.draw(),访问已销毁对象的内存必然引发异常。
  • 位置判断逻辑有漏洞:原代码先移动再判断xPos是否为0,若逻辑出错导致xPos跳过0,就不会触发销毁逻辑。

修复方案

针对Arduino资源有限的特性,更稳妥的方式是用状态标记替代对象销毁,既避免内存问题,又能实现敌人“消失+重生”的效果:

修正后的完整代码

#include <LiquidCrystal.h>

// LCD与按键引脚定义
const int rs = 7, en = 8, d4 = 9, d5 = 10, d6 = 11, d7 = 12, buttonPin = 2;
LiquidCrystal lcd = LiquidCrystal(rs, en, d4, d5, d6, d7);

// 游戏变量
unsigned int playerYPos = 1, buttonPrevious;
const long playerUpdateInterval = 32, enemyMoveInterval = 500;
unsigned long lastUpdatedPlayerMillis = 0, lastMovedEnemiesMillis;

class Enemy {
private:
  int xPos, yPos;
  bool isActive; // 标记敌人是否处于活跃状态
public:
  Enemy(int xPos, int yPos) {
    this->xPos = xPos;
    this->yPos = yPos;
    isActive = true; // 初始化时默认活跃
  }

  void draw() {
    if(isActive){ // 仅绘制活跃的敌人
      lcd.setCursor(xPos, yPos);
      lcd.print("E");
    }
  }

  void move() {
    if(!isActive) return; // 非活跃敌人不执行移动逻辑

    // 擦除当前位置的敌人
    lcd.setCursor(xPos, yPos);
    lcd.print(" ");

    xPos--;
    // 当敌人移动到屏幕左边界外时,标记为非活跃
    if(xPos < 0){ 
      isActive = false;
    }
  }

  // 重置敌人位置,实现重生
  void reset(int newX, int newY){
    isActive = true;
    xPos = newX;
    yPos = newY;
  }

  // 获取敌人活跃状态
  bool isEnemyActive(){
    return isActive;
  }
};

Enemy e(15, 1);

void drawPlayer() {
  lcd.setCursor(1, playerYPos);
  lcd.print("P");
}

void updatePlayer() {
  uint8_t button = digitalRead(buttonPin);
  // 检测按键按下的边缘触发
  if (button == LOW && buttonPrevious == HIGH) {
    // 擦除原位置的玩家
    lcd.setCursor(1, playerYPos);
    lcd.print(" ");
    // 切换玩家行位置(0和1互转)
    playerYPos = 1 - playerYPos;
  }
  buttonPrevious = digitalRead(buttonPin);
}

void setup() {
  lcd.begin(16, 2);
  pinMode(buttonPin, INPUT_PULLUP);
  buttonPrevious = digitalRead(buttonPin);
  Serial.begin(9600);
}

void loop() {
  unsigned long currentMillis = millis();

  // 定时更新玩家状态
  if (currentMillis - lastUpdatedPlayerMillis >= playerUpdateInterval) {
    lastUpdatedPlayerMillis = currentMillis;
    updatePlayer();
  }

  // 定时移动敌人
  if(currentMillis - lastMovedEnemiesMillis >= enemyMoveInterval) {
    lastMovedEnemiesMillis = currentMillis;
    e.move();
    // 敌人非活跃时,随机行重新生成
    if(!e.isEnemyActive()){
      e.reset(15, random(0,2));
    }
  }

  drawPlayer();
  e.draw();
}

关键修改说明

  1. 新增isActive成员变量:用状态标记替代对象销毁,避免内存操作风险
  2. 优化move方法:非活跃敌人直接跳过移动逻辑,到达边界时标记为非活跃并擦除
  3. 新增reset方法:实现敌人重生,无需频繁创建销毁对象,节省Arduino内存
  4. 补充重生逻辑:敌人消失后自动在屏幕右侧随机行重新生成,符合无限跑酷的玩法

内容的提问来源于stack exchange,提问作者TitanJamison

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 19:00:53