C++实现植物大战僵尸模拟:如何跟踪植物僵尸实例处理回合动作
实现建议
第一步:优化基类设计,统一状态与动作接口
给Plant和Zombie基类增加通用属性与虚函数,所有差异化逻辑放在派生类实现:
// Plant基类新增内容 class Plant { protected: int hp; int cost; int attack; public: virtual ~Plant() = default; virtual void act(Game& game, int row, int col) = 0; // 每回合动作接口 void take_damage(int dmg) { hp -= dmg; } bool is_dead() const { return hp <= 0; } int get_cost() const { return cost; } virtual std::string get_plant_type() const = 0; }; // Long_thrower派生类示例 class Long_thrower : public Plant { public: Long_thrower() { hp = 3; cost = 2; attack = 1; } void act(Game& game, int row, int col) override { // 找同row、距离>=3格的最近僵尸 Zombie* target = nullptr; for (int c = col + 3; c < 10; c++) { // 僵尸只在右侧,从最近的开始找 auto& zombies = game.get_square(row, c).get_zombies(); if (!zombies.empty()) { target = zombies[0]; // 取最前的僵尸 break; } } if (target) target->take_damage(attack); } std::string get_plant_type() const override { return "Long_thrower"; } }; // Potato派生类示例 class Potato : public Plant { public: Potato() { hp = 4; cost =4; attack =0; } void act(Game& game, int row, int col) override {} // 无攻击逻辑 std::string get_plant_type() const override { return "Potato"; } }; // Zombie基类新增内容 class Zombie { protected: int hp; int attack; public: virtual ~Zombie() = default; virtual void act(Game& game, int row, int col, size_t zombie_idx) = 0; void take_damage(int dmg) { hp -= dmg; } bool is_dead() const { return hp <=0; } }; // 普通僵尸派生类示例 class NormalZombie : public Zombie { public: NormalZombie() { hp =3; attack =1; } void act(Game& game, int row, int col, size_t zombie_idx) override { // 先判断左边格子有没有植物 Square& left_sq = game.get_square(row, col-1); if (left_sq.get_plant() && !left_sq.get_plant()->is_dead()) { left_sq.get_plant()->take_damage(attack); return; } // 没有植物就左移 Square& curr_sq = game.get_square(row, col); Zombie* self = curr_sq.get_zombies()[zombie_idx]; left_sq.add_zombie(self); curr_sq.remove_zombie(zombie_idx); } };
第二步:调整Square类结构适配规则
规则限定每格最多1株植物,无需用vector存植物,优化后结构:
class Square{ private: Plant* plant = nullptr; vector<Zombie*> zombies; public: ~Square() { delete plant; for (auto z : zombies) delete z; } // 植物相关接口 Plant* get_plant() const { return plant; } bool has_plant() const { return plant != nullptr && !plant->is_dead(); } void set_plant(Plant* p) { delete plant; plant = p; } // 僵尸相关接口 vector<Zombie*>& get_zombies() { return zombies; } void add_zombie(Zombie* z) { zombies.push_back(z); } void remove_zombie(size_t idx) { zombies.erase(zombies.begin() + idx); } // 清理本格死亡单位 void clear_dead() { if (plant && plant->is_dead()) { delete plant; plant = nullptr; } for (auto it = zombies.begin(); it != zombies.end();) { if ((*it)->is_dead()) { delete *it; it = zombies.erase(it); } else { ++it; } } } };
同时Game类新增获取对应格子的接口:
class Game{ protected: bool gameover; int foodbank; vector<vector<Square>> room; public: Game() : room(8, vector<Square>(10)), gameover(false), foodbank(5) {} // 初始食物可自定义 Square& get_square(int row, int col) { return room[row][col]; } void run_round(); // 单回合执行入口 // 其余成员待补充 };
第三步:实现单回合流程控制
严格按照规则的4步实现run_round方法:
void Game::run_round() { // 步骤1:每行列9(第10格)生成普通僵尸 for (int i = 0; i < 8; i++) { room[i][9].add_zombie(new NormalZombie()); } // 步骤2:玩家放置植物逻辑(你已实现,这里补充后续植物攻击) // 【你原有放置植物的逻辑写在这里】 // 所有植物执行动作 for (int row = 0; row < 8; row++) { for (int col = 0; col < 10; col++) { if (room[row][col].has_plant()) { room[row][col].get_plant()->act(*this, row, col); } } } // 清理第一轮死亡单位 for (int row = 0; row <8; row++) { for (int col =0; col <10; col++) { room[row][col].clear_dead(); } } // 步骤3:僵尸执行动作,注意每行从右往左遍历,避免重复移动 for (int row = 0; row <8; row++) { for (int col =9; col >=1; col--) { // 第0列的僵尸已经获胜,不需要处理 auto& zombies = room[row][col].get_zombies(); // 逆序遍历僵尸,避免删除元素导致索引错乱 for (int z_idx = zombies.size() -1; z_idx >=0; z_idx--) { zombies[z_idx]->act(*this, row, col, z_idx); } } } // 清理第二轮死亡单位 for (int row = 0; row <8; row++) { for (int col =0; col <10; col++) { room[row][col].clear_dead(); } } // 步骤4:胜负判定 // 检查是否有僵尸到第0列 for (int row =0; row <8; row++) { if (!room[row][0].get_zombies().empty()) { gameover = true; cout << "僵尸获胜!" << endl; return; } } // 检查是否所有僵尸都被清除 bool all_zombie_dead = true; for (int row =0; row <8; row++) { for (int col =0; col <10; col++) { if (!room[row][col].get_zombies().empty()) { all_zombie_dead = false; break; } } if (!all_zombie_dead) break; } if (all_zombie_dead) { gameover = true; cout << "植物获胜!" << endl; return; } }
第四步:状态跟踪说明
所有单位的生命值、属性都存储在各自的实例对象中,每回合执行动作时直接操作对应实例的属性,死亡后由Square的clear_dead方法统一释放内存、移除无效指针,不会再参与后续回合的逻辑计算。
如果需要额外统计存活单位数量,也可以在Game类里维护两个全局的存活植物、僵尸链表,每次增减单位时同步更新链表,比每次遍历全棋盘效率更高,对这个8*10的小棋盘来说两种方式都可以。
内容的提问来源于stack exchange,提问作者vmilk-
相关产品推荐
相关产品推荐

