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

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-

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 00:24:03