ESP32数字消消乐小游戏:按键灯带加LCD

2026-10-30 09:36:44 56阅读
[

一、项目概述

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

核心玩法

  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 DINGPIO275V 供电,与 ESP32 共地
LCD1602 SDAGPIO21I2C 数据线
LCD1602 SCLGPIO22I2C 时钟线
LCD1602 VCC5V背光需 5V,3.3V 可能偏暗
LCD1602 GNDGND共地

注意:灯带与 LCD 电流较大,建议外部 5V 供电并与 ESP32 共地,避免烧录时电压不稳导致上传失败。

3D结构图

按键外壳设计

第一个版本漏开了安装LCD的位置,有需要的老师可以留言,我改完再上传。

数字消消乐游戏成品

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

按键与灯带接线实物

LCD显示与灯带效果
游戏运行实拍

三、软件环境与依赖

  • 开发板: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


]

硬件清单

    [
  • [红色街机按键60#]1
  • [绿色街机按键60#]1
  • [蓝色街机按键60#]1
  • LCD1602字符液晶显示器1
  • [esp32模块]1
  • [ws2812全彩灯带]1
  • [3D打印件]1
  • ]
    [
  • LED_entertainment.zip
  • ]


作者:MRX
链接:https://www.aiddithome.com/p/12ca543fbc59ae.html
本作遵循 [CC BY 4.0 署名] 许可,版权归作者所有。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
4条评论
刷着刷着入坑了
1楼 · 2026-10-30 09:39:18

实测数据挺有参考价值

阿伟不emo
2楼 · 2026-10-30 09:39:16

本地跑不用联网这点很加分

装过才知道
3楼 · 2026-10-30 09:39:15

这个思路可以扩展不少玩法

默默点赞的路人
4楼 · 2026-10-30 09:39:14

看完手痒了,准备动手