系列最后一篇:一个"剧情向"的文本 RPG,没有画面,全靠文字和想象力。玩家冒险、战斗、捡装备吃药水,把类、std::vectorstd::map 和随机数串起来。

玩法介绍

四个地点:村庄回血、森林与城堡打怪、山洞捡宝箱。回合制战斗,击败得经验;血低喝药续命。

第 1 步:玩家类 Player

玩家属性装进 Player 类:血量、攻击、等级、经验,以及 std::vector<std::string> 背包。gainExp() 用 while 处理连升多级:

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <random>

class Player {
public:
    std::string name;
    int hp, maxHp, atk, level, exp;
    std::vector<std::string> bag;

    Player(const std::string& n)
        : name(n), hp(30), maxHp(30), atk(5), level(1), exp(0) {}

    void heal(int amount) {
        hp += amount;
        if (hp > maxHp) hp = maxHp;
    }

    void gainExp(int e) {
        exp += e;
        while (exp >= level * 10) {
            exp -= level * 10;
            ++level;
            maxHp += 10;
            hp = maxHp;
            atk += 2;
            std::cout << "升级!Lv." << level << "\n";
        }
    }
};

第 2 步:怪物与回合制战斗

怪物用 struct 表示,makeMonster() 按等级随机生成属性。战斗:选攻击,双方互相扣血,击败得经验:

struct Monster {
    std::string name;
    int hp, atk;
};

Monster makeMonster(int lv) {
    static const std::vector<std::string> names = {"史莱姆", "野狼", "骷髅"};
    std::mt19937 g(std::random_device{}());
    std::uniform_int_distribution<int> pick(0, (int)names.size() - 1);
    std::uniform_int_distribution<int> hpR(10 + lv * 3, 15 + lv * 4);
    std::uniform_int_distribution<int> atkR(2 + lv, 3 + lv * 2);
    return {names[pick(g)], hpR(g), atkR(g)};
}

void battle(Player& p, Monster m) {
    std::cout << "遭遇 " << m.name << "!\n";
    while (p.hp > 0 && m.hp > 0) {
        std::cout << "按 1 攻击: ";
        int cmd;
        std::cin >> cmd;
        m.hp -= p.atk;
        p.hp -= m.atk;
        std::cout << "你打它 " << p.atk << ",它打你 " << m.atk << "\n";
    }
    if (p.hp > 0) {
        int r = 8 + p.level * 3;
        p.gainExp(r);
        std::cout << "击败 " << m.name << ",得 " << r << " 经验!\n";
    }
}

第 3 步:用 std::map 搭建地图

地图是"地点名 → 描述"的映射,适合 std::map。加地点只需在 buildMap() 里加一行:

std::map<std::string, std::string> buildMap() {
    std::map<std::string, std::string> m;
    m["村庄"] = "和平之地,可以休息。";
    m["森林"] = "野兽出没。";
    m["山洞"] = "黑暗的山洞,有宝箱。";
    m["城堡"] = "冒险的终点。";
    return m;
}

第 4 步:背包系统

背包就是 std::vector<std::string>:push_back 捡、empty 判空、pop_back 用。主循环里三行代码完成"判断 → 使用 → 回血":

// 背包三件套:push_back 捡、empty 判空、pop_back 用
if (!hero.bag.empty()) {
    std::cout << "喝下 " << hero.bag.back() << ",+15 HP。\n";
    hero.bag.pop_back();
    hero.heal(15);
}

第 5 步:主循环与编译运行

主循环负责显示地图、选择地点、触发事件。把第 1~4 步的代码与下面的 main() 存进 rpg.cpp:

int main() {
    std::cout << "=== 文本 RPG ===\n";
    Player hero("勇者");
    std::map<std::string, std::string> places = buildMap();

    while (hero.hp > 0) {
        std::cout << "\nHP " << hero.hp << "/" << hero.maxHp
                  << " Lv." << hero.level << " 背包 " << hero.bag.size() << " 件\n";
        for (const auto& [place, desc] : places)
            std::cout << "[" << place << "] " << desc << "\n";
        std::cout << "去哪? ";
        std::string dest;
        std::cin >> dest;
        if (!places.count(dest)) {
            std::cout << "没这地方。\n";
            continue;
        }
        if (dest == "村庄") {
            hero.heal(999);
            std::cout << "休息一晚,HP 回满。\n";
        } else if (dest == "山洞") {
            hero.bag.push_back("治疗药水");
            std::cout << "宝箱!获得 治疗药水。\n";
        } else {
            battle(hero, makeMonster(hero.level));
        }
        if (hero.hp < hero.maxHp / 2 && !hero.bag.empty()) {
            std::cout << "喝药?(1 喝 / 0 不喝): ";
            int use;
            std::cin >> use;
            if (use == 1) {
                std::cout << "喝下 " << hero.bag.back() << ",+15 HP。\n";
                hero.bag.pop_back();
                hero.heal(15);
            }
        }
    }
    std::cout << "你倒下了……\n";
    return 0;
}
g++ -std=c++17 -o rpg rpg.cpp
./rpg
💡 改进方向:① 用 std::map 做技能表;② 商店系统;③ 存档/读档;④ 随机事件,让每次探索不一样。