Files
chouka/lesson_gui_6.cpp
2026-05-16 12:05:04 +08:00

153 lines
5.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// =====================================================================
// 第 6 课:完整抽卡游戏 —— 起步骨架
// 教程文件:第06课-完整抽卡游戏.md
// 完整答案:solutions/lesson_gui_6.cpp
// 起步状态:第 5 课结束的样子(卡片名字 + 分区布局)
// 这一课要做的:金币系统 + 累计统计 + 重置/退出按钮 + 函数复用
// =====================================================================
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Box.H>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <string>
// ===== 卡片数据 =====
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_callbackwindow->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();
}