// ===================================================================== // 第 6 课:完整抽卡游戏 —— 起步骨架 // 教程文件:第06课-完整抽卡游戏.md // 完整答案:solutions/lesson_gui_6.cpp // 起步状态:第 5 课结束的样子(卡片名字 + 分区布局) // 这一课要做的:金币系统 + 累计统计 + 重置/退出按钮 + 函数复用 // ===================================================================== #include #include #include #include #include #include #include #include // ===== 卡片数据 ===== std::string normal_cards[5] = { "小火龙", "水跃鱼", "绿草龟", "小电鼠", "土拨仔" }; std::string rare_cards[5] = { "烈焰飞龙", "冰霜之狼", "暗影豹", "风暴鹰", "水晶鹿" }; std::string super_cards[3] = { "雷霆神龙", "凤凰王", "深海巨兽" }; // TODO(步骤 2):在这里加游戏状态变量 // int coins = 500; // int total_normal = 0, total_rare = 0, total_super = 0; // ===== 全局控件 ===== // TODO(步骤 1):把 window 也升级成全局变量,下面 main 里别忘了去掉局部声明 Fl_Box *result_box; Fl_Box *stats_box; // TODO(步骤 2):再声明一个 Fl_Box *coins_box; // TODO(步骤 2):辅助函数 update_coins_display(),把 coins 显示到 coins_box // TODO(步骤 3):辅助函数 update_stats_display(),把累计统计显示到 stats_box // TODO(步骤 4):把"抽一张卡"的逻辑封装成 std::string get_card(int &rare_level) // 函数内:随机 → 判断 → 累加 total_* 统计 → 返回卡名 // 两个回调都调用它,不要重复写 void draw_one_callback(Fl_Widget *w, void *data) { // TODO(步骤 2):先检查金币是否够 10,不够就提示并 return // TODO(步骤 2):扣 10 金币 → update_coins_display() int r = std::rand() % 100; std::string result = ""; std::string card_name = ""; if (r < 70) { result = "☆ 普通卡 ☆"; card_name = normal_cards[std::rand() % 5]; result_box->labelcolor(fl_rgb_color(128, 128, 128)); } else if (r < 95) { result = "★ 稀有卡 ★"; card_name = rare_cards[std::rand() % 5]; result_box->labelcolor(FL_BLUE); } else { result = "★★★ 超稀有卡!! ★★★"; card_name = super_cards[std::rand() % 3]; result_box->labelcolor(FL_RED); } std::string display = result + "\n " + card_name + "\n"; result_box->labelsize(24); result_box->label(display.c_str()); // TODO(步骤 3):抽完后 update_stats_display() // TODO(步骤 4):用 get_card() 替换上面整个 if/else/else,让代码不重复 } void draw_ten_callback(Fl_Widget *w, void *data) { // TODO(步骤 2):先检查金币是否够 100,不够就提示并 return // TODO(步骤 2):扣 100 金币 → update_coins_display() std::string all = ""; int rare_count = 0; int super_count = 0; for (int i = 1; i <= 10; i++) { int r = std::rand() % 100; all += "第" + std::to_string(i) + "抽:"; if (r < 70) { all += "普通 " + normal_cards[std::rand() % 5]; } else if (r < 95) { all += "★稀有 " + rare_cards[std::rand() % 5]; rare_count++; } else { all += "★★★超稀有 " + super_cards[std::rand() % 3]; super_count++; } all += "\n"; } result_box->labelsize(15); result_box->label(all.c_str()); result_box->labelcolor(FL_BLACK); char stats[100]; std::sprintf(stats, "十连:普通 %d | 稀有 %d | 超稀有 %d", 10 - rare_count - super_count, rare_count, super_count); stats_box->label(stats); stats_box->labelcolor(super_count > 0 ? FL_RED : FL_BLUE); // TODO(步骤 3):改成调用 update_stats_display() 显示**累计**统计 // TODO(步骤 4):用 get_card() 替换上面循环里的 if/else,让代码不重复 } // TODO(步骤 5):在这里写 reset_callback:金币和统计全部清零、刷新显示 // TODO(步骤 6):在这里写 quit_callback:window->hide(); int main() { std::srand(std::time(nullptr)); // TODO(步骤 1):把窗口宽改成 440,高改成 560,标题改成 "抽卡大冒险" // 注意:window 已经是全局变量了,这里不要再写 Fl_Window * Fl_Window *window = new Fl_Window(420, 520, "抽卡世界 - 第5课"); Fl_Button *btn1 = new Fl_Button(40, 15, 150, 45, "抽一张"); btn1->labelsize(18); btn1->callback(draw_one_callback); Fl_Button *btn10 = new Fl_Button(230, 15, 150, 45, "十连抽"); btn10->labelsize(18); btn10->callback(draw_ten_callback); // TODO(步骤 2):在这里创建 coins_box // 位置 (30, 75)、宽 380、高 30、字号 20、加粗 // 然后调一次 update_coins_display() result_box = new Fl_Box(20, 80, 380, 350, "点击按钮开始抽卡!"); result_box->labelsize(22); result_box->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); result_box->box(FL_DOWN_BOX); stats_box = new Fl_Box(20, 445, 380, 40, "等待抽卡..."); stats_box->labelsize(14); stats_box->box(FL_FLAT_BOX); stats_box->color(fl_rgb_color(230, 230, 230)); // TODO(步骤 5):加 "重置" 按钮,位置 (100, 450)、宽 100、高 40,绑定 reset_callback // TODO(步骤 6):加 "退出" 按钮,位置 (240, 450)、宽 100、高 40,绑定 quit_callback window->end(); window->show(); return Fl::run(); }