数字消消乐

2026-10-074

一、项目概述

这是一个考验反应速度与颜色判断的小游戏。随机彩色灯珠从灯带顶端不断向底端移动,玩家需在其抵达底端前,按下对应颜色的按键发射同色灯珠将其消除。撞错颜色或让灯珠逃到底端即挑战失败。

核心玩法

  1. 启动:上电后依次按下 红 → 绿 → 蓝 三个按键启动游戏。
  2. 随机灯组:灯带顶端随机生成 1~5 颗灯珠,每颗颜色在红/绿/蓝中独立随机,整体向 0 号移动。
  3. 玩家发射:游戏中按 红/绿/蓝 键,从 0 号位置生成对应颜色灯珠,向 41 号移动。
  4. 碰撞判定:
    • 同色相遇 → 双方消隐,得 1 分
    • 异色相遇 → 挑战失败
    • 随机灯珠未被消除、越过 0 号 → 挑战失败
  5. 难度递增:每正确消除 10 个,移动速度加快 50ms。
  6. 计分:当前分与最高分显示在 LCD 上,最高分掉电保存。
  7. 结束动画:
    • 普通结束 → 全灯红色闪烁 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的位置,有需要的老师可以留言,我改完再上传。

数字消消乐_image_1.webp

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

数字消消乐_image_2.webp

数字消消乐_image_3.webp
数字消消乐_image_4.webp


三、软件环境与依赖

  • 开发板: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(namespace ledgame,key highscore),掉电不丢。

六、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 背光亮但无字

  1. 对比度:拧模块背面蓝色电位器,直到字符显现。
  2. I2C 地址:打开串口监视器(115200),把日志里的真实地址填入 LCD_ADDR。
  3. 接线:确认 SDA=GPIO21、SCL=GPIO22、VCC=5V、共地。

八、演示视频

数字消消乐_哔哩哔哩_bilibili

硬件清单

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -

创作许可协议

本项目采用 CC BY(署名) 进行许可。

相关推荐

所需材料/产品

LCD1602字符液晶显示器

LCD1602字符液晶显示器

LCD1602字符液晶显示器