DIY Arduino LCD 游戏机:16x2 字符屏打造“躲避防守队员”足球小游戏
组件与物料清单
| 组件 | 数量 | 备注 |
|---|---|---|
| 10kΩ 电阻 | 2 | 一个用于 LCD 对比度,一个用于按钮下拉(注意:原手册示例为上拉,本项目采用下拉接法) |
| 1kΩ 电阻 | 1 | LCD 对比度分压 |
| 12mm 轻触按键 | 1 | |
| Adafruit 16x2 白字蓝底 LCD | 1 | 需自行焊接排针 |
| Arduino UNO | 1 | |
| 跳线 | 若干 |
项目背景
因主项目延期,决定利用闲置 Arduino 套件练手。首次使用 LCD1602,顺便自学了焊接排针。最初跑官方例程只能跑马灯显示文本,随后学习 LiquidCrystal 库,写了个数字“0”在屏上弹跳的小程序,萌生了做游戏的念头。网上找到的 LCD 游戏代码过于复杂,遂自行设计了这款简单的“躲避防守队员”游戏。
硬件连接
- 按原理图连接 LCD 引脚(RS、EN、D4~D7 分别接 Arduino 4、6、10、11、12、13)。
- 对比度调节:原用 10k 电位器,实测阻值后改用 1k + 10k 串联固定电阻分压,接 VO 引脚。
- 按键接在面包板上,信号线接 Arduino D8,采用 10kΩ 下拉电阻(按下为高电平)。
- 上传代码即可运行。

游戏玩法
- 你控制底部的足球运动员(自定义字符),防守队员从右侧向左移动逼近。
- 开机显示开场动画,提示“Hit the button...”时按下按键开始。
- 防守队员靠近时按键使球员跳起(显示跳跃动作),落地后继续奔跑。
- 每过一关防守队员速度加快(延迟减少 20ms),共 10 关。
- 若未及时跳跃被碰到,游戏结束,根据得分显示评价:<10 满分“Congratulations!”,<3 “You suck”,3~5 “Not bad!”,6~9 “Great!”。
角色与障碍物字符由在线生成工具 LCD Character Generator 制作,包含跑步两帧、跳跃、防守跑动两帧、滑铲共 6 个自定义字符。
完整代码
/* Dodge the defs!! - 躲避防守队员
* Created by Shreyas R P, 2018-06-21
* GPL v3 License
*/
#include <LiquidCrystal.h>
const int btn = 8; // 按键引脚
// 开场文本
char* introText[] = {"Dodge the defs!!", "Created on:", "Hit the button..."};
// 状态变量
int game = 0;
int buttonPress = 0, buttonState = 0;
int obstaclePos, obsDelay, score = 0;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;
int lastButtonState = LOW;
// 自定义字符 (8x5 点阵)
byte runnin1[8] = {0b01100,0b01100,0b00000,0b11100,0b01110,0b01100,0b11110,0b00011};
byte runnin2[8] = {0b00110,0b00110,0b00000,0b00111,0b01110,0b00110,0b01110,0b00101};
byte jump[8] = {0b00100,0b01100,0b11100,0b01110,0b01100,0b11111,0b00000,0b00001};
byte def1[8] = {0b00100,0b00110,0b00111,0b01110,0b00110,0b01111,0b01000,0b00000};
byte def2[8] = {0b00100,0b00110,0b00111,0b01110,0b00110,0b00110,0b00110,0b00010};
byte slide[8] = {0b00000,0b00000,0b00011,0b00011,0b00000,0b01111,0b11111,0b00000};
LiquidCrystal lcd(4,6,10,11,12,13);
void setup() {
Serial.begin(9600);
pinMode(btn, INPUT);
lcd.begin(16,2);
lcd.createChar(0, runnin1);
lcd.createChar(1, runnin2);
lcd.createChar(2, jump);
lcd.createChar(3, def1);
lcd.createChar(4, def2);
lcd.createChar(5, slide);
buttonState = digitalRead(btn);
}
void loop() {
intro();
while (game == 1) ballActive();
endGame();
}
void intro() {
score = 0;
lcd.clear(); lcd.print(introText[0]);
lcd.setCursor(7,1); lcd.print("By SRP888"); delay(2000);
lcd.clear(); lcd.print(introText[1]);
lcd.setCursor(0,1); lcd.print("21-06-2018"); delay(2000);
lcd.clear();
while (button() != 1) { // 等待按键
lcd.setCursor(0,0); lcd.print(introText[2]); delay(100);
}
game = 1;
}
void reset() {
// 交替显示两帧跑步动画
if (obstaclePos % 2 == 0) { lcd.clear(); lcd.setCursor(0,1); lcd.write(byte(0)); }
else { lcd.clear(); lcd.setCursor(0,1); lcd.write(1); }
}
void ballActive() {
obsDelay = 200; // 初始延迟
obstaclePos = 15; // 从最右列开始
while (game == 1) {
reset();
if (button() == 1) { // 按键跳跃
lcd.clear(); lcd.setCursor(0,0); lcd.write(2); // 显示跳跃
obstacle(obstaclePos);
delay(400); // 保持显示
lcd.clear(); lcd.setCursor(0,1); lcd.write(1); // 落地
obstacle(obstaclePos);
} else {
if (obstaclePos != 0) { reset(); obstacle(obstaclePos); }
else { game = 0; break; } // 被撞到
}
obstaclePos--;
if (obstaclePos < 0) { // 成功躲过
obsDelay -= 20; // 加速
obstaclePos = 15;
score++;
}
if (obsDelay == 0) game = 0; // 10 关通过
delay(obsDelay);
}
}
// 按键消抖,返回 1 表示按下
int button() {
int reading = digitalRead(btn);
if (reading != lastButtonState) lastDebounceTime = millis();
if ((millis() - lastDebounceTime) > debounceDelay) {
buttonState = reading;
if (buttonState == HIGH) { lastButtonState = reading; return 1; }
}
lastButtonState = reading;
return 0;
}
void obstacle(int i) {
if (obstaclePos % 2 == 0 && obstaclePos > 2) { lcd.setCursor(i,1); lcd.write(3); }
else if (obstaclePos % 2 != 0 && obstaclePos > 2) { lcd.setCursor(i,1); lcd.write(4); }
else { lcd.setCursor(i,1); lcd.write(5); } // 近距离滑铲
}
void endGame() {
lcd.clear();
if (score == 10) { lcd.print("Congratulations!"); lcd.setCursor(0,1); lcd.print("You beat 'em all"); }
else if (score < 3) { lcd.print("You suck"); lcd.setCursor(0,1); lcd.print("Score: "); lcd.print(score); }
else if (score < 6) { lcd.print("Not bad!"); lcd.setCursor(0,1); lcd.print("Score: "); lcd.print(score); }
else { lcd.print("Great!"); lcd.setCursor(0,1); lcd.print("Score: "); lcd.print(score); }
delay(3000);
}
原理图

制造工艺
- 工业触摸屏维修实战:95% 可用通用件替代 OEM 原厂件,艾伦·布拉德利案例实证
- 快速原型为何是产品开发制胜关键:从虚拟到实体的必经之路
- 掌控产品设计:攻克常见挑战的实证策略全景图
- 液晶显示器(LCD):技术、制造与未来展望
- 树莓派专业温度监测:基于 DS18B20 传感器的完整指南
- Primal Display:树莓派 LCD 温度监测仪
- Drone Pi:双模Multiwii+树莓派四轴飞行器,支持手机与遥控器控制
- Archimedes:情感感知 AI 机器猫头鹰
- Walbi:基于 Arduino 与 LX-16A 舵机的稳健双足机器人
- 2024吹叶机选购指南:按需匹配才是最优解
- 四极管:设计、功能与放大器性能影响
- 战略性数据溯源:构建韧性供应链的关键钥匙