数字消消乐
2026-10-074
一、项目概述
这是一个考验反应速度与颜色判断的小游戏。随机彩色灯珠从灯带顶端不断向底端移动,玩家需在其抵达底端前,按下对应颜色的按键发射同色灯珠将其消除。撞错颜色或让灯珠逃到底端即挑战失败。
核心玩法
- 启动:上电后依次按下 红 → 绿 → 蓝 三个按键启动游戏。
- 随机灯组:灯带顶端随机生成 1~5 颗灯珠,每颗颜色在红/绿/蓝中独立随机,整体向 0 号移动。
- 玩家发射:游戏中按 红/绿/蓝 键,从 0 号位置生成对应颜色灯珠,向 41 号移动。
- 碰撞判定:
- 同色相遇 → 双方消隐,得 1 分
- 异色相遇 → 挑战失败
- 随机灯珠未被消除、越过 0 号 → 挑战失败
- 难度递增:每正确消除 10 个,移动速度加快 50ms。
- 计分:当前分与最高分显示在 LCD 上,最高分掉电保存。
- 结束动画:
- 普通结束 → 全灯红色闪烁 3 次
- 刷新最高分 → 七彩流水灯效持续 3 秒
- 结束后需再次按 红→绿→蓝 重新启动
二、硬件清单
硬件接线图
| 模块 | 引脚 | 说明 |
|---|---|---|
| 红色按键 | GPIO14 | 另一端接 GND(内部上拉) |
| 绿色按键 | GPIO12 | 另一端接 GND(内部上拉) |
| 蓝色按键 | GPIO13 | 另一端接 GND(内部上拉) |
| WS2812 DIN | GPIO27 | 5V 供电,与 ESP32 共地 |
| LCD1602 SDA | GPIO21 | I2C 数据线 |
| LCD1602 SCL | GPIO22 | I2C 时钟线 |
| LCD1602 VCC | 5V | 背光需 5V,3.3V 可能偏暗 |
| LCD1602 GND | GND | 共地 |
注意:灯带与 LCD 电流较大,建议外部 5V 供电并与 ESP32 共地,避免烧录时电压不稳导致上传失败。
3D结构图
按键外壳设计
第一个版本漏开了安装LCD的位置,有需要的老师可以留言,我改完再上传。

安装完按键后,按键本体内带有灯珠,可以直接5V长亮。



三、软件环境与依赖
- 开发板:ESP32 Dev Module
- 编程工具:ArduinoIDE
- 依赖库:
Adafruit NeoPixel— WS2812 灯带驱动LiquidCrystal_I2C— LCD1602 I2C 驱动
四、可调参数
#define NUM_LEDS 42 // 灯珠数量
#define DEBOUNCE_MS 20 // 按键消抖时间
#define MOVE_INTERVAL_MS 350 // 初始移动间隔(越大越慢)
#define SPEED_STEP_MS 50 // 每档加速减少的间隔
#define ELIM_PER_LEVEL 10 // 每消除多少个加速一次
#define MIN_MOVE_INTERVAL 80 // 最快速度下限
#define LCD_ADDR 0x22
#define LCD_SDA 21
#define LCD_SCL 22
调试时可把
MOVE_INTERVAL_MS调大(如 500~800)放慢速度便于观察。
五、软件架构
5.1 游戏状态机
GS_START_SEQ ──(按对 R→G→B)──▶ GS_PLAYING
▲ │
│ │ 失败(异色/逃逸)
└────────(动画结束)──────── GS_GAME_OVER
| 状态 | 含义 |
|---|---|
GS_START_SEQ |
等待依次按下 红→绿→蓝,按错则重置 |
GS_PLAYING |
游戏进行,灯珠移动与碰撞判定 |
GS_GAME_OVER |
播放结束动画后回到启动序列 |
5.2 灯珠实体模型
将灯珠所有关键状态封装在一个简单的结构体中,可以简化碰撞检测和画面渲染的逻辑复杂度:
struct Entity {
int pos; // 位置 0..41
uint32_t color; // 颜色
int dir; // +1 = 玩家(0→41), -1 = 随机(41→0)
bool alive; // 是否存活
};
5.3 核心模块与函数
| 函数 | 职责 |
|---|---|
setup() |
初始化串口、GPIO、灯带、扫描 I2C 探测 LCD 地址、读取最高分 |
updateButton() / consumePress() |
三变量消抖 + 下降沿事件检测 |
spawnPlayerLED() |
按键在 0 号位置生成玩家灯珠 |
spawnRandomGroup() |
顶端生成 1~5 颗随机颜色灯组 |
resolveCollisions() |
碰撞判定:同色消除得分,异色判负 |
drawAll() |
渲染所有存活灯珠到灯带 |
startNewGame() |
重置分数/速度,开始新一局 |
finishGameOver() |
结束动画 + LCD 提示 + 回到启动序列 |
updateLCD() / showRestartPrompt() |
LCD 分数/提示显示 |
5.4 碰撞与移动时序
阶段0 resolveCollisions() 处理已同位的灯珠(含 0 号位最后机会)
阶段A 随机灯珠 pos-- 若 pos<0 未消除 → 逃逸判负
resolveCollisions()
阶段B 玩家灯珠 pos++ 越过 41 号则消失
resolveCollisions()
阶段C 无随机灯珠存活 → spawnRandomGroup()
drawAll()
两阶段移动(随机先动、玩家后动)配合多次碰撞判定,确保相邻靠近的灯珠不会「擦肩而过」漏判,同时给停在 0 号位的灯珠保留被同色消除的最后机会。
5.5 计分与难度
- 每消除一对 +1 分,
score实时更新到 LCD。 eliminateCount每达 10 的倍数,moveInterval减 50ms(下限 80ms)。- 刷新最高分时立即写入
Preferences(namespaceledgame,keyhighscore),掉电不丢。
六、LCD 显示流程
上电/重启后 游戏中 游戏结束
───────────── ─────────── ──────────────
Press R->G->B Score: 12 GAME OVER (1.2s)
to start High: 30 NEW RECORD! / High:xx
→ Press R->G->B to start
启动序列中 LCD 实时提示进度:R OK → Now press G、R G OK → Now press B。
七、常见问题排查
LCD 背光亮但无字
- 对比度:拧模块背面蓝色电位器,直到字符显现。
- I2C 地址:打开串口监视器(115200),把日志里的真实地址填入
LCD_ADDR。 - 接线:确认 SDA=GPIO21、SCL=GPIO22、VCC=5V、共地。
八、演示视频
硬件清单
- 红色街机按键60#1
- 绿色街机按键60#1
- 蓝色街机按键60#1
- LCD1602字符液晶显示器1
- esp32模块1
- ws2812全彩灯带1
- 3D打印件1



