5.6 KiB
5.6 KiB
第 3 课:随机抽卡——核心来了
本课目标:点击按钮 → 随机出"普通卡 / 稀有卡 / 超稀有卡",结果显示在窗口里。把命令行抽卡逻辑搬进 GUI。
复习:第 2 课学会了按钮和回调;命令行时期你已掌握 rand()、srand()、if/else。
1. 这一课要搞懂什么
把以前学过的三样东西组合进一个 GUI 程序:
| 老朋友 | 在 GUI 里怎么用 |
|---|---|
srand(time(...)) |
在 main 开头调一次(和以前一样) |
rand() % 100 |
放在回调函数里,每次点击执行 |
if / else if / else |
放在回调函数里,根据 r 决定显示什么 |
关键区别:以前判断完用 cout 打印,现在用 label() 更新窗口上的文字。
2. 稀有度与颜色搭配
本课不仅显示文字,还用不同颜色区分稀有度:
| 随机数 r | 稀有度 | 文字颜色 | 概率 |
|---|---|---|---|
| 0 ~ 69 | 普通卡 | 灰色 | ~70% |
| 70 ~ 94 | 稀有卡 | 蓝色 | ~25% |
| 95 ~ 99 | 超稀有卡! | 红色 | ~5% |
颜色让稀有卡一眼就能看出来——比命令行效果震撼多了。
3. 完整示例程序
保存为 lesson_gui_3.cpp:
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Box.H>
#include <cstdlib> // rand, srand
#include <ctime> // time
// 全局变量
Fl_Box *result_box;
Fl_Box *info_box; // 显示本次点数的辅助信息
// 回调函数——每次点击按钮执行
void draw_callback(Fl_Widget *w, void *data) {
int r = std::rand() % 100;
// 显示点数(调试用,熟悉后可以删掉这行)
char info[50];
std::sprintf(info, "本次点数:%d", r);
info_box->label(info);
// 判断稀有度
if (r < 70) {
result_box->label("☆ 普通卡 ☆");
result_box->labelcolor(fl_rgb_color(128, 128, 128)); // 灰色
} else if (r < 95) {
result_box->label("★ 稀有卡 ★");
result_box->labelcolor(FL_BLUE); // 蓝色
} else {
result_box->label("★★★ 超稀有卡!! ★★★");
result_box->labelcolor(FL_RED); // 红色
}
}
int main() {
std::srand(std::time(nullptr)); // 种子设一次
Fl_Window *window = new Fl_Window(400, 350, "抽卡世界 - 第3课");
// 抽卡按钮
Fl_Button *btn = new Fl_Button(130, 30, 140, 50, "🎴 抽一张!");
btn->labelsize(18);
btn->callback(draw_callback);
// 结果标签(大字号)
result_box = new Fl_Box(50, 110, 300, 80, "点击按钮抽卡吧!");
result_box->labelsize(28);
result_box->labelfont(FL_BOLD);
// 信息标签(小字号,显示点数)
info_box = new Fl_Box(50, 200, 300, 50, "");
info_box->labelsize(14);
window->end();
window->show();
return Fl::run();
}
4. 新知识点
sprintf —— 把数字变成字符串
char info[50];
std::sprintf(info, "本次点数:%d", r);
info_box->label(info);
以前你可能会写:
std::cout << "本次点数:" << r << "\n";
但 FLTK 的 label() 只能接受一个字符串。sprintf 把数字塞进字符串里——%d 的位置被 r 的值替换。
fl_rgb_color —— 自定义颜色
fl_rgb_color(128, 128, 128) // R=128, G=128, B=128 → 灰色
fl_rgb_color(255, 200, 0) // → 金色
- R(红)、G(绿)、B(蓝),每个 0~255
- 试试不同的数值创造你自己的颜色!
5. 运行效果
┌───────── 抽卡世界 - 第3课 ────────┐
│ │
│ ┌──────────────┐ │
│ │ 🎴 抽一张! │ │
│ └──────────────┘ │
│ │
│ ★ 稀有卡 ★ │ ← 蓝色大字
│ │
│ 本次点数:78 │ ← 小字
│ │
└─────────────────────────────────────┘
连续点击多次,观察普通(灰)、稀有(蓝)、超稀有(红)的分布。超稀有大约 20 次出 1 次。
6. 本课课堂小练习
- 调概率:把
r < 70改成r < 50,把r < 95改成r < 85。看看稀有和超稀有是不是变多了。 - 把"超稀有卡"的颜色改成金色
fl_rgb_color(255, 200, 0)。 - 给超稀有卡多加一行"🎉恭喜!"——提示:可以改
info_box的内容。
7. 本课课后作业(选做)
- 增加第四个稀有度:"传说卡"(
r >= 99),颜色用金色,概率约 1%。和旧课程第 5 课的练习类似,但现在是 GUI 版本。 - 把按钮文字改成"再抽一次"。
- 试着把窗口上所有文字都换成你自己喜欢的卡牌主题(比如"SSR""SR""R"等)。
8. 常见小问题
- 每次结果都一样:检查
srand(time(nullptr))是否在main里、是否只写了一次。写在回调里会导致每次点按钮重置种子。 - 缺少
#include <cstdlib>或<ctime>:报rand/srand/time未定义。 sprintf缓冲区太小:如果信息很长,char info[50]可以改成char info[100]。
9. 下一课预告
第 4 课做十连抽:加一个"十连抽"按钮,用 for 循环一口气生成 10 个结果,全部显示在窗口里。
学完请在 学习进度与状态-GUI.md 里更新第 3 课的状态。
下一课文档:第04课-十连抽.md