save code
This commit is contained in:
+183
@@ -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`
|
||||
Reference in New Issue
Block a user