save code

This commit is contained in:
xsl
2026-05-16 11:09:02 +08:00
parent 478b3451a1
commit a169ceb263
45 changed files with 2226 additions and 0 deletions
+183
View File
@@ -0,0 +1,183 @@
# 第 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`
```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 —— 把数字变成字符串
```cpp
char info[50];
std::sprintf(info, "本次点数:%d", r);
info_box->label(info);
```
以前你可能会写:
```cpp
std::cout << "本次点数:" << r << "\n";
```
但 FLTK 的 `label()` 只能接受一个字符串。`sprintf` 把数字塞进字符串里——`%d` 的位置被 `r` 的值替换。
### fl_rgb_color —— 自定义颜色
```cpp
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. 本课课堂小练习
1. 调概率:把 `r < 70` 改成 `r < 50`,把 `r < 95` 改成 `r < 85`。看看稀有和超稀有是不是变多了。
2. 把"超稀有卡"的颜色改成金色 `fl_rgb_color(255, 200, 0)`
3. 给超稀有卡多加一行"🎉恭喜!"——提示:可以改 `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`