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(); }
关键修改说明
- 新增
isActive成员变量:用状态标记替代对象销毁,避免内存操作风险 - 优化
move方法:非活跃敌人直接跳过移动逻辑,到达边界时标记为非活跃并擦除 - 新增
reset方法:实现敌人重生,无需频繁创建销毁对象,节省Arduino内存 - 补充重生逻辑:敌人消失后自动在屏幕右侧随机行重新生成,符合无限跑酷的玩法
内容的提问来源于stack exchange,提问作者TitanJamison
相关产品推荐
相关产品推荐

