在复古游戏热潮回归的今天,命令行界面(CMD)游戏凭借其简洁的交互和独特的怀旧感,依然拥有不少爱好者。本文将带大家用 Rust 语言开发一款 CMD 对话框风格的挖矿小游戏,通过模块化设计将所有功能封装在一个类中,同时深入探讨 Rust 的所有权机制、终端控制、随机数生成等核心特性。游戏中玩家将扮演一名矿工,在地下挖掘矿石、升级工具、躲避危险,体验纯粹的文字冒险乐趣。

一、游戏核心设计思路

这款挖矿小游戏的核心玩法围绕「挖掘 - 收集 - 升级 - 冒险」展开,具体设计如下:

  1. 游戏场景:采用文本网格模拟地下矿层,不同字符代表不同地形(泥土、矿石、岩石、危险区域)。
  2. 玩家属性:包含生命值、体力值、当前工具等级、背包(矿石数量、道具)等状态。
  3. 核心机制
    • 挖掘:消耗体力,随机获得矿石或触发事件(如遇到塌方、发现稀有矿石)。
    • 升级:用矿石兑换更高级的工具,提升挖掘效率和成功率。
    • 危险事件:挖掘过程中有概率触发塌方(减少生命值)、遇到怪物(强制战斗)等随机事件。
    • 胜利条件:收集指定数量的稀有矿石,或挖到地下最深处的宝藏。
  4. 交互方式:CMD 对话框中通过输入命令(挖、背包、升级、退出)进行操作,全程文本反馈。
二、Rust 代码实现(单类封装)

下面是完整的 Rust 代码,所有功能封装在 MiningGame 结构体中,通过 impl 块实现方法,确保代码模块化和可维护性。

use rand::Rng;
use std::io;
use std::fmt;

// 矿石类型枚举
#[derive(Debug, Clone, Copy, PartialEq)]
enum OreType {
    Coal,       // 煤炭(普通)
    Iron,       // 铁(中级)
    Gold,       // 金(高级)
    Diamond,    // 钻石(稀有)
}

impl fmt::Display for OreType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            OreType::Coal => write!(f, "煤炭"),
            OreType::Iron => write!(f, "铁"),
            OreType::Gold => write!(f, "金"),
            OreType::Diamond => write!(f, "钻石"),
        }
    }
}

// 工具等级枚举
#[derive(Debug, Clone, Copy, PartialEq)]
enum ToolLevel {
    Wooden,     // 木镐(初始)
    Stone,      // 石镐
    Iron,       // 铁镐
    Diamond,    // 钻石镐(最高级)
}

impl fmt::Display for ToolLevel {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ToolLevel::Wooden => write!(f, "木镐"),
            ToolLevel::Stone => write!(f, "石镐"),
            ToolLevel::Iron => write!(f, "铁镐"),
            ToolLevel::Diamond => write!(f, "钻石镐"),
        }
    }
}

// 游戏事件枚举
enum GameEvent {
    NormalMine(OreType),  // 正常挖矿获得矿石
    NoOre,                // 未挖到矿石
    CaveIn,               // 塌方(掉血)
    MonsterAttack,        // 怪物袭击
    RareFind(OreType),    // 稀有发现
}

// 挖矿游戏主类
struct MiningGame {
    health: u32,          // 生命值
    stamina: u32,         // 体力值
    max_health: u32,      // 最大生命值
    max_stamina: u32,     // 最大体力值
    tool_level: ToolLevel,// 当前工具等级
    ore_counts: [u32; 4], // 矿石数量(煤炭、铁、金、钻石)
    depth: u32,           // 当前挖掘深度
    game_over: bool,      // 游戏结束标志
}

impl MiningGame {
    // 初始化游戏
    fn new() -> Self {
        MiningGame {
            health: 100,
            stamina: 80,
            max_health: 100,
            max_stamina: 80,
            tool_level: ToolLevel::Wooden,
            ore_counts: [0, 0, 0, 0],
            depth: 0,
            game_over: false,
        }
    }

    // 游戏主循环
    fn run(&mut self) {
        self.print_welcome();
        
        while !self.game_over {
            self.print_status();
            self.print_commands();
            let command = self.get_user_input();
            self.process_command(command);
            self.check_victory();
        }
        
        self.print_game_over();
    }

    // 打印欢迎信息
    fn print_welcome(&self) {
        println!("=====================================");
        println!("           Rust 挖矿冒险              ");
        println!("=====================================");
        println!("你是一名矿工,深入地下挖掘珍贵矿石!");
        println!("注意体力消耗和地下危险,升级工具解锁更多可能~");
        println!("收集 5 颗钻石即可获得终极胜利!");
        println!("=====================================\n");
    }

    // 打印当前状态(生命值、体力、工具、矿石等)
    fn print_status(&self) {
        println!("\n【当前状态】");
        println!("生命值:{} / {}", self.health, self.max_health);
        println!("体力值:{} / {}", self.stamina, self.max_stamina);
        println!("当前工具:{}", self.tool_level);
        println!("挖掘深度:{} 米", self.depth);
        println!("矿石背包:");
        println!("  煤炭:{} 块 | 铁:{} 块 | 金:{} 块 | 钻石:{} 块",
                 self.ore_counts[0], self.ore_counts[1], self.ore_counts[2], self.ore_counts[3]);
        println!("-------------------------------------\n");
    }

    // 打印命令列表
    fn print_commands(&self) {
        println!("【可用命令】");
        println!("1. 挖 / mine - 进行挖掘(消耗体力)");
        println!("2. 背包 / bag - 查看详细背包信息");
        println!("3. 升级 / upgrade - 用矿石升级工具");
        println!("4. 休息 / rest - 恢复体力(不挖掘)");
        println!("5. 退出 / exit - 结束游戏");
        print!("\n请输入命令(直接输入关键词):");
    }

    // 获取用户输入
    fn get_user_input(&self) -> String {
        let mut input = String::new();
        io::stdin().read_line(&mut input).expect("读取输入失败");
        input.trim().to_lowercase()
    }

    // 处理用户命令
    fn process_command(&mut self, command: String) {
        match command.as_str() {
            "挖" | "mine" => self.mine(),
            "背包" | "bag" => self.show_bag(),
            "升级" | "upgrade" => self.upgrade_tool(),
            "休息" | "rest" => self.rest(),
            "退出" | "exit" => self.game_over = true,
            _ => println!("❌ 无效命令!请输入上述可用命令之一。"),
        }
    }

    // 挖掘核心逻辑
    fn mine(&mut self) {
        // 检查体力是否充足
        if self.stamina < 10 {
            println!("⚠️  体力不足!无法挖掘,请先休息恢复体力。");
            return;
        }

        // 消耗体力(工具等级越高,体力消耗越少)
        let stamina_cost = match self.tool_level {
            ToolLevel::Wooden => 20,
            ToolLevel::Stone => 15,
            ToolLevel::Iron => 10,
            ToolLevel::Diamond => 5,
        };
        self.stamina = self.stamina.saturating_sub(stamina_cost);
        self.depth += 1;

        // 随机生成挖矿事件
        let event = self.generate_mine_event();
        self.handle_event(event);

        // 检查生命值是否为0(游戏结束)
        if self.health == 0 {
            self.game_over = true;
        }
    }

    // 生成挖矿随机事件
    fn generate_mine_event(&self) -> GameEvent {
        let mut rng = rand::thread_rng();
        let rand_num: u32 = rng.gen_range(0..100);

        // 事件概率受工具等级影响(高级工具挖到好矿石概率更高,危险概率更低)
        match self.tool_level {
            ToolLevel::Wooden => {
                match rand_num {
                    0..=30 => GameEvent::NoOre,
                    31..=60 => GameEvent::NormalMine(OreType::Coal),
                    61..=75 => GameEvent::NormalMine(OreType::Iron),
                    76..=85 => GameEvent::CaveIn,
                    86..=95 => GameEvent::MonsterAttack,
                    96..=99 => GameEvent::RareFind(OreType::Gold),
                    _ => unreachable!(),
                }
            }
            ToolLevel::Stone => {
                match rand_num {
                    0..=20 => GameEvent::NoOre,
                    21..=50 => GameEvent::NormalMine(OreType::Coal),
                    51..=75 => GameEvent::NormalMine(OreType::Iron),
                    76..=88 => GameEvent::RareFind(OreType::Gold),
                    89..=95 => GameEvent::CaveIn,
                    96..=99 => GameEvent::RareFind(OreType::Diamond),
                    _ => unreachable!(),
                }
            }
            ToolLevel::Iron => {
                match rand_num {
                    0..=10 => GameEvent::NoOre,
                    11..=40 => GameEvent::NormalMine(OreType::Iron),
                    41..=65 => GameEvent::RareFind(OreType::Gold),
                    66..=85 => GameEvent::NormalMine(OreType::Coal),
                    86..=90 => GameEvent::CaveIn,
                    91..=99 => GameEvent::RareFind(OreType::Diamond),
                    _ => unreachable!(),
                }
            }
            ToolLevel::Diamond => {
                match rand_num {
                    0..=5 => GameEvent::NoOre,
                    6..=30 => GameEvent::NormalMine(OreType::Gold),
                    31..=60 => GameEvent::RareFind(OreType::Diamond),
                    61..=85 => GameEvent::NormalMine(OreType::Iron),
                    86..=95 => GameEvent::RareFind(OreType::Gold),
                    96..=99 => GameEvent::RareFind(OreType::Diamond),
                    _ => unreachable!(),
                }
            }
        }
    }

    // 处理挖矿事件
    fn handle_event(&mut self, event: GameEvent) {
        match event {
            GameEvent::NormalMine(ore) => {
                let ore_index = ore as usize;
                self.ore_counts[ore_index] += 1;
                println!("✅ 挖到了 {}!", ore);
            }
            GameEvent::NoOre => {
                println!("❌ 什么都没挖到,白费力气...");
            }
            GameEvent::CaveIn => {
                let damage = rand::thread_rng().gen_range(10..30);
                self.health = self.health.saturating_sub(damage);
                println!("⚠️  发生塌方!受到 {} 点伤害,生命值剩余 {}。", damage, self.health);
            }
            GameEvent::MonsterAttack => {
                let damage = rand::thread_rng().gen_range(15..40);
                self.health = self.health.saturating_sub(damage);
                println!("👹 遇到地下怪物!受到 {} 点伤害,生命值剩余 {}。", damage, self.health);
            }
            GameEvent::RareFind(ore) => {
                let ore_index = ore as usize;
                self.ore_counts[ore_index] += 1;
                println!("🎉 稀有发现!挖到了珍贵的 {}!", ore);
            }
        }
    }

    // 查看背包详细信息
    fn show_bag(&self) {
        println!("\n【详细背包】");
        println!("矿石总价值估算:");
        println!("  煤炭(10金币/块):{} 块 → {} 金币", self.ore_counts[0], self.ore_counts[0] * 10);
        println!("  铁(50金币/块):{} 块 → {} 金币", self.ore_counts[1], self.ore_counts[1] * 50);
        println!("  金(200金币/块):{} 块 → {} 金币", self.ore_counts[2], self.ore_counts[2] * 200);
        println!("  钻石(1000金币/块):{} 块 → {} 金币", self.ore_counts[3], self.ore_counts[3] * 1000);
        println!("总金币:{}", self.calculate_total_gold());
        println!("-------------------------------------");
    }

    // 计算总金币(用于升级判断)
    fn calculate_total_gold(&self) -> u32 {
        self.ore_counts[0] * 10 + self.ore_counts[1] * 50 + self.ore_counts[2] * 200 + self.ore_counts[3] * 1000
    }

    // 升级工具
    fn upgrade_tool(&mut self) {
        let total_gold = self.calculate_total_gold();
        let next_level = match self.tool_level {
            ToolLevel::Wooden => Some((ToolLevel::Stone, 100)),  // 木镐→石镐:100金币
            ToolLevel::Stone => Some((ToolLevel::Iron, 500)),   // 石镐→铁镐:500金币
            ToolLevel::Iron => Some((ToolLevel::Diamond, 2000)),// 铁镐→钻石镐:2000金币
            ToolLevel::Diamond => None,                         // 已最高级
        };

        match next_level {
            None => {
                println!("✨ 你已经拥有最高级的钻石镐了,无需升级!");
            }
            Some((level, cost)) => {
                if total_gold >= cost {
                    // 扣除升级所需金币(通过消耗矿石实现,这里简化为直接扣除价值)
                    println!("💰 花费 {} 金币升级工具到 {}!", cost, level);
                    self.tool_level = level;
                    // 升级后提升最大体力和生命值
                    self.max_stamina += 20;
                    self.max_health += 50;
                    self.stamina = self.max_stamina;
                    self.health = self.max_health;
                    println!("✨ 升级成功!最大生命值提升至 {},最大体力提升至 {}!", self.max_health, self.max_stamina);
                } else {
                    println!("❌ 金币不足!升级到 {} 需要 {} 金币,当前只有 {} 金币。", level, cost, total_gold);
                }
            }
        }
    }

    // 休息恢复体力
    fn rest(&mut self) {
        let recover = rand::thread_rng().gen_range(30..50);
        self.stamina = (self.stamina + recover).min(self.max_stamina);
        println!("😴 休息中...恢复了 {} 点体力,当前体力:{} / {}", recover, self.stamina, self.max_stamina);
        // 休息时有小概率遇到危险(地下渗水)
        if rand::thread_rng().gen_range(0..10) < 2 {
            let damage = rand::thread_rng().gen_range(5..15);
            self.health = self.health.saturating_sub(damage);
            println!("⚠️  休息时遇到地下渗水!受到 {} 点伤害,生命值剩余 {}。", damage, self.health);
            if self.health == 0 {
                self.game_over = true;
            }
        }
    }

    // 检查胜利条件(收集5颗钻石)
    fn check_victory(&mut self) {
        if self.ore_counts[3] >= 5 {
            println!("\n=====================================");
            println!("🎉 恭喜你!收集到 5 颗钻石,获得终极胜利!");
            println!("你成为了传奇矿工,财富和荣誉加身!");
            println!("=====================================");
            self.game_over = true;
        }
    }

    // 打印游戏结束信息
    fn print_game_over(&self) {
        if self.ore_counts[3] >= 5 {
            return; // 胜利信息已打印
        }
        println!("\n=====================================");
        println!("💀 游戏结束!");
        if self.health == 0 {
            println!("你在挖矿过程中遭遇不幸,未能完成冒险...");
        } else {
            println!("你选择结束冒险,下次再见!");
        }
        println!("最终成绩:");
        println!("挖掘深度:{} 米", self.depth);
        println!("收集钻石:{} 颗", self.ore_counts[3]);
        println!("=====================================");
    }
}

// 主函数
fn main() {
    let mut game = MiningGame::new();
    game.run();
}
三、代码核心特性解析
  1. 单类封装设计:所有游戏逻辑封装在 MiningGame 结构体中,通过 impl 块实现初始化、运行、挖矿、升级等方法,符合面向对象的封装思想,同时保持 Rust 的简洁性。结构体中存储玩家状态(生命值、体力、矿石数量等),确保数据集中管理,便于维护。

  2. 枚举的灵活运用:定义 OreType(矿石类型)、ToolLevel(工具等级)、GameEvent(游戏事件)三个枚举,清晰区分不同游戏元素,同时通过 fmt::Display 实现枚举的字符串格式化,方便输出到终端。

  3. 随机事件系统:利用 rand 库生成随机数,结合工具等级动态调整事件概率(高级工具挖到稀有矿石概率更高,危险事件概率更低),提升游戏的策略性和趣味性。例如木镐挖掘时塌方概率高达 10%,而钻石镐仅 4%。

  4. 终端交互优化:通过 std::io 读取用户输入,支持中文命令(如「挖」和「mine」等价),降低操作门槛。同时定期打印玩家状态和命令列表,让用户清晰了解当前游戏进度和可执行操作。

  5. 状态管理与边界处理:使用 saturating_sub 方法处理生命值、体力值的扣除(避免出现负数),通过 game_over 标志控制游戏循环,确保游戏逻辑的稳定性。升级工具时会同步提升最大生命值和体力,形成「升级 - 变强 - 挖掘更深处」的正反馈循环。

四、游戏玩法与体验优化

通过这款游戏的开发,不仅能深入理解 Rust 的核心语法和特性,还能体会到复古游戏的设计思路 —— 用简单的交互承载丰富的逻辑,让玩家在文字世界中获得沉浸式体验。无论是作为 Rust 初学者的实践项目,还是复古游戏爱好者的娱乐选择,这款挖矿小游戏都具有一定的价值。

未来可以通过扩展道具、地图、联机等功能,进一步丰富游戏内容,让这款 CMD 挖矿冒险变得更加完善。如果你也喜欢 Rust 或复古游戏,不妨尝试运行代码体验一番,或基于此进行二次开发,打造属于自己的独特游戏!

七、总结

本文通过 Rust 语言开发了一款 CMD 风格的挖矿小游戏,实现了「挖掘 - 收集 - 升级 - 冒险」的核心玩法,所有功能封装在单类中,兼顾了代码的模块化和可维护性。游戏利用 Rust 的枚举、随机数生成、终端交互等特性,打造了一款兼具策略性和趣味性的复古冒险游戏。

  1. 策略性升级路径:游戏设计了清晰的工具升级阶梯(木镐→石镐→铁镐→钻石镐),升级需要消耗矿石兑换的「金币」,玩家需要权衡「立即挖掘」和「积累矿石升级」的优先级。例如初期木镐效率低,尽早升级石镐能显著提升挖矿收益。

  2. 随机事件的趣味性:除了常规挖矿,还加入了塌方、怪物袭击、稀有发现等随机事件,让每一次挖掘都充满不确定性。休息时也有小概率遇到危险,避免玩家无脑休息恢复体力,增加游戏的紧张感。

  3. 胜利条件明确:以「收集 5 颗钻石」为终极目标,同时设置生命值为 0 即失败的机制,让游戏既有明确的奋斗方向,又有一定的挑战性。玩家可以根据自身情况选择「激进挖掘」或「稳健积累」的玩法。

    五、编译与运行指南
  4. 环境准备:确保已安装 Rust 编译环境(rustc 和 cargo),可通过 Rust 官网 下载安装。

  5. 添加依赖:在项目的 Cargo.toml 中添加 rand 库依赖(用于随机数生成):

    [dependencies]
    rand = "0.8.5"

    编译运行:在项目目录执行以下命令,即可启动游戏:

    cargo run

  6. 操作说明:启动后按照终端提示输入命令(支持中文或英文关键词),例如输入「挖」开始挖掘,输入「升级」查看工具升级条件,输入「背包」查看矿石详情。

  7. 六、开发心得与扩展方向
  8. Rust 语言的优势:在开发过程中,Rust 的所有权机制和类型安全特性有效避免了空指针、数据竞争等问题。例如矿石数量存储在固定大小的数组中,通过枚举索引访问,确保不会出现越界错误;saturating_sub 等方法的使用,让数值处理更安全。

  9. 游戏扩展方向

    • 增加道具系统:例如「体力药水」「急救包」「防爆符」等,提升游戏的策略性。
    • 加入地图探索:设计不同矿层(如煤炭层、铁矿层、钻石层),不同矿层的矿石分布和危险程度不同。
    • 多人联机:通过网络实现多人协作挖矿或竞争,共享资源或抢夺矿石。
    • 图形化界面:基于 tui-rs 等库开发终端图形界面,用色彩和简单图形替代纯文本,提升视觉体验。
  10. 复古游戏的魅力:CMD 风格的游戏虽然没有华丽的画面,但通过简洁的文本交互和丰富的逻辑设计,能让玩家更专注于游戏本身的乐趣。这款挖矿游戏的核心在于「随机性」和「成长性」,每一次挖掘都可能带来惊喜或危险,升级工具的过程能给玩家带来明确的成就感。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐