ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

用Arduino Esplora做游戏机:从贪吃蛇到PC手柄的完整实践

2026/8/27 2:34:04 拓冰建站 浏览量
用Arduino Esplora做游戏机:从贪吃蛇到PC手柄的完整实践 Arduino Esplora 这块板子在很多人眼里可能是个异类它不像 UNO 那样需要外接一堆杜邦线也不像 Nano 那样纯粹为嵌入式原型而生。它长着一张手柄脸自带摇杆、按键、蜂鸣器、RGB 灯甚至内置了麦克风和加速度计。我第一次拿到它的时候第一反应就是这不就是一块为打游戏而生的开发板吗顺着这个思路做下去我陆续完成了贪吃蛇掌机、PC 游戏手柄、体感控制小游戏等项目Esplora 的潜力远比官方示例里那几行传感器打印程序要大得多。如果你手里正好也有一块吃灰的 Esplora或者正考虑入手但不知道它能干嘛这篇文章会比较适合你。我会从硬件特性拆解讲到环境配置再给两个能直接跑起来的游戏项目——一个是带屏幕的贪吃蛇一个是模拟键盘鼠标的 PC 手柄最后把我在实际调试中踩过的坑都列出来。全程不绕弯子都是可以直接复现的内容。1. 拆开这台游戏掌机Esplora 硬件到底藏了什么1.1 输入侧摇杆、按键和运动传感器比普通开发板多了一整套交互Esplora 最显眼的自然是那个模拟摇杆。这个摇杆输出两个模拟量X 轴和 Y 轴分别对应左右和前后。读取方式是Esplora.readJoystickX()和Esplora.readJoystickY()数值范围是 0 到 1023居中大约在 512 附近。还有一个Esplora.readJoystickSwitch()用来读取摇杆垂直向下按压的状态相当于一颗额外的确认键。摇杆旁边是四个独立的按键官方叫法是 LEFT_BUTTON、RIGHT_BUTTON、UP_BUTTON、DOWN_BUTTON分别对应字母 D、F、G、H 在键盘上的位置。这个布局很有意思——它不是简单的十字键而是像游戏手柄的 ABXY 那样分布在右侧配合左手摇杆正好是一套标准的双输入方案。还有两个容易被忽略的输入线性加速度计和侧边的滑动电阻。加速度计可以感知板子的倾斜角度和运动状态这意味着你不需要额外买任何模块就能做出体感控制游戏。滑动电阻则是一个模拟量输入可以当作游戏里的油门、音量、速度调节或者任意你需要的连续控制量。1.2 输出侧蜂鸣器、RGB LED 和屏幕接口反馈链条一应俱全输入有了输出也没落下。Esplora 板载了一个压电蜂鸣器用Esplora.tone(frequency, duration)就能播放音效不需要外接任何喇叭。旁边是两颗 RGB LED分别位于板子的左上角和右上角用Esplora.writeRGB(red, green, blue)一行代码就能改变颜色和亮度。这两颗 LED 在游戏里可以当生命值、得分提示、状态闪烁用起来非常顺手。屏幕也是 Esplora 的一大特色。它通过板子右侧的专用接口连接 Esplora TFT 屏幕这个屏幕是 Arduino 官方为 Esplora 设计的扩展模块插上就能用不需要额外接一堆线。驱动库用的是 Arduino TFT 库初始化方法和普通的显示屏模块略有区别但画点、画线、画矩形、显示文字这些基本功能都有。接上屏幕后Esplora 就变成了一台真正的掌上游戏机而不是只能连电脑才能玩的半成品。1.3 核心芯片 ATmega32U4能模拟键盘鼠标的板子才配叫游戏外设Esplora 的处理器是 ATmega32U4这一点和 Arduino Leonardo 同源。这颗芯片最大的特点是原生支持 USB HID也就是说它可以通过 USB 直接模拟键盘和鼠标不需要任何外部芯片。这个能力在游戏项目里是杀手级的把 Esplora 插到电脑上它可以像一个标准键盘那样发送按键事件或者像一个鼠标那样移动光标、点击按钮。UNO/Nano 用的 ATmega328P 就没有这个能力因为它的 USB 转串口芯片只能模拟串口不能模拟 HID 设备。这也是为什么用 UNO 做游戏手柄必须额外购买 USB Host Shield 或者改造硬件而 Esplora 开箱即是手柄。这个差异不是性能问题而是芯片架构决定的做游戏类项目时选型要特别留意。2. 开工前的环境准备装库、选板卡、解决串口不识别2.1 Arduino IDE 和 Esplora 库版本搭配要这样选Esplora 是 2012 年发布的老板子但它在 Arduino IDE 中的支持依然完好。你只需要打开 Arduino IDE在工具 - 开发板 - 开发板管理器里搜索Arduino AVR Boards并安装Esplora 就在这个包里不需要单独安装板卡支持。IDE 版本方面我用的是 Arduino IDE 1.8.19 和 2.x 系列都试过2.x 的串口监视器对 Esplora 的兼容性也没有问题。关键点是 Esplora 库。早期版本 IDE 会把 Esplora 相关函数内置在核心库里但如果你用的是新版本 IDE可能需要手动安装Esplora库。在项目 - 加载库 - 管理库里搜索Esplora找到 Arduino 官方维护的版本安装即可。安装完之后随便打开一个示例比如 File - Examples - Esplora - EsploraReadAll如果能正常编译说明环境基本就绪。2.2 驱动装不上、COM 口不出现先检查这两个地方Esplora 插上电脑后正常情况会识别为一个串口设备显示 COM 口。但很多人会遇到两种情况一是设备管理器里压根不出现 COM 口而是出现一个带黄色感叹号的未知设备二是 COM 口出现了但打开串口监视器后程序没有反应。第一种情况十有八九是数据线的问题。Esplora 是一个 USB 设备需要一根能传输数据的 USB 线不是随便找一根只能充电的线就行。我调试时用过一根手机充电线插上后只显示充电模式设备管理器里永远看不到 COM 口换了一根带数据传输的线立刻好了。如果你确认数据线没问题再检查驱动。Windows 下 ATmega32U4 通常会自动安装驱动如果不行可以试试手动安装 Arduino 驱动包或者换个 USB 口插拔一次。第二种情况串口监视器打不开或没有输出通常是波特率没配对。Esplora 的 Serial.begin() 默认常用 9600但有些示例代码写的是 57600 或 115200串口监视器右下角的波特率没有对应改成相同值自然什么都看不到。这不算 bug纯属操作习惯问题。2.3 第一个测试程序把摇杆和按键数据读上来环境没问题之后先跑一个最基础的读取程序把 Esplora 的输入都打印到串口监视器。代码如下#include Esplora.h void setup() { Serial.begin(9600); while (!Serial) { // 等待 USB 串口连接尤其在 Leonardo/Esplora 上必须加 delay(10); } Serial.println(Esplora test start); } void loop() { int joyX Esplora.readJoystickX(); int joyY Esplora.readJoystickY(); int joyBtn Esplora.readJoystickSwitch(); int btnLeft Esplora.readButton(LEFT_BUTTON); int btnRight Esplora.readButton(RIGHT_BUTTON); int accelX Esplora.readAccelerometer(X_AXIS); int accelY Esplora.readAccelerometer(Y_AXIS); Serial.print(JX:); Serial.print(joyX); Serial.print( JY:); Serial.print(joyY); Serial.print( JB:); Serial.print(joyBtn); Serial.print( BL:); Serial.print(btnLeft); Serial.print( BR:); Serial.print(btnRight); Serial.print( AX:); Serial.print(accelX); Serial.print( AY:); Serial.print(accelY); Serial.println(); delay(100); }这里有一个值得注意的细节在 Leonardo 和 Esplora 上串口初始化后必须加一个while (!Serial)等待循环。因为 ATmega32U4 的 USB 串口是虚拟的需要电脑端完成枚举后才能通信。不加这行的话程序一开始的 Serial 输出很可能会丢失。把代码烧录进去之后打开串口监视器拨动摇杆观察数字变化。摇杆居中时 JX 和 JY 应该接近 512向左右上下推时数值会偏移到 0 或 1023 附近。按钮按下时对应变量会变成 LOW。这一步先确认每个输入都正常后面的游戏项目才不会玄学。3. 项目实战贪吃蛇掌机把原生输入输出全部用上3.1 TFT 屏幕接入与显示初始化贪吃蛇是游戏开发里的 Hello World但它足够完整地检验一块硬件的输入、处理、输出能力。我用的屏幕是官方 Esplora TFT 模块与 Esplora 通过屏幕接口连接。它的接口定义是这样的引脚连接目标CS10DC9RESET8MOSI、SCK硬件 SPI 接口GND、5V电源与地初始化代码用 Arduino 官方 TFT 库#include TFT.h TFT tft(10, 9, 8); // CS, DC, RESET void setup() { tft.begin(); tft.background(0, 0, 0); }要注意的是TFT库的构造函数参数顺序是 CS、DC、RESET不要搞反。如果屏幕一直白屏或花屏先检查这三个引脚定义再看是不是 SPI 引脚冲突。Esplora 的 TFT 接口已经和板载 SPI 连好不需要额外接线。3.2 游戏状态机设计移动、吃豆、碰撞、结束贪吃蛇游戏的核心逻辑我拆成了四个状态移动、吃食物、判断碰撞、结束。用一个简单状态机作为loop()的主线enum GameState { GAME_RUNNING, GAME_OVER }; GameState gameState GAME_RUNNING;loop()里每次循环读取输入、更新蛇的坐标、检测是否吃到食物、检测是否撞墙或撞自己最后重绘屏幕。方向控制不能直接改成相反方向否则蛇会瞬间掉头撞到自己所以每次读输入后都会判断一下新方向是否和当前方向相反。3.3 核心代码逐段拆解这里我给一个精简版的核心逻辑不是完整代码但主要流程都在#include Esplora.h #include TFT.h TFT tft(10, 9, 8); const int COLS 16; const int ROWS 16; const int CELL 6; int snakeX[100], snakeY[100]; int snakeLen 3; int dirX 1, dirY 0; int foodX, foodY; void setup() { randomSeed(analogRead(0)); tft.begin(); tft.background(0, 0, 0); snakeX[0] 4; snakeY[0] 8; snakeX[1] 3; snakeY[1] 8; snakeX[2] 2; snakeY[2] 8; generateFood(); drawAll(); } void loop() { readDirection(); moveSnake(); if (checkCollision()) { tft.stroke(255, 0, 0); tft.setTextSize(2); tft.text(GAME OVER, 8, 40); while (true) { // 等待复位 } } drawAll(); delay(250); } void readDirection() { int x Esplora.readJoystickX(); int y Esplora.readJoystickY(); if (x 400 dirX ! 1) { dirX -1; dirY 0; } else if (x 600 dirX ! -1) { dirX 1; dirY 0; } else if (y 400 dirY ! 1) { dirX 0; dirY -1; } else if (y 600 dirY ! -1) { dirX 0; dirY 1; } } void moveSnake() { for (int i snakeLen - 1; i 0; i--) { snakeX[i] snakeX[i - 1]; snakeY[i] snakeY[i - 1]; } snakeX[0] dirX; snakeY[0] dirY; if (snakeX[0] foodX snakeY[0] foodY) { snakeLen; generateFood(); Esplora.tone(880, 80); } } bool checkCollision() { if (snakeX[0] 0 || snakeX[0] COLS || snakeY[0] 0 || snakeY[0] ROWS) { return true; } for (int i 1; i snakeLen; i) { if (snakeX[i] snakeX[0] snakeY[i] snakeY[0]) { return true; } } return false; } void drawAll() { tft.background(0, 0, 0); tft.stroke(255, 255, 0); tft.fill(255, 255, 0); tft.rect(foodX * CELL, foodY * CELL, CELL, CELL); tft.stroke(0, 255, 0); tft.fill(0, 255, 0); for (int i 0; i snakeLen; i) { tft.rect(snakeX[i] * CELL, snakeY[i] * CELL, CELL, CELL); } }代码里用了randomSeed(analogRead(0))来初始化随机数。如果你不调这一行每次开机食物位置可能完全一样因为 Arduino 的random()默认种子是固定的。analogRead(0)读取的是引脚 A0 的悬空噪声值每次上电都不同作为种子足够。另一个细节是delay(250)。这个值决定了蛇的移动速度。250 毫秒一帧对初玩者比较友好但如果你玩顺手了想挑战可以改成 150 毫秒甚至 100 毫秒。实际测试中Esplora 的摇杆手感比较轻在 150 毫秒的速度下操控性依然不错。3.4 手感与可玩性调整的细节贪吃蛇这个项目看起来简单但实际玩起来有几个手感问题需要注意。第一个是方向检测的死区。摇杆居中时会有小幅抖动所以判断方向时我用了 400 和 600 两个阈值而不是 512。如果你的摇杆有偏移风这个值要重新校准否则可能出现不推摇杆但蛇自己拐弯的情况。第二个是食物生成位置。最简单的做法是random(0, COLS)和random(0, ROWS)但可能会出现食物生成在蛇身上的情况。我在实际项目中加了一个检查如果生成的位置和蛇身重合就重新生成。这个逻辑虽然简单但能避免很多卡住的尴尬。第三个是音效反馈。每次吃到食物我用Esplora.tone(880, 80)播放一个短音给玩家一个即时的正向反馈。这个反馈在游戏体验里很重要没有声音的游戏会显得很呆。4. 让 Esplora 变身 PC 游戏手柄键盘与鼠标模拟4.1 为什么 Esplora 能做到而 UNO 做不到前面已经提到过 ATmega32U4 支持原生 USB HID这是 Esplora 作为 PC 游戏手柄的技术基础。具体来说Esplora 通过 USB 枚举成一个标准键盘或鼠标设备电脑会把它的按键事件当作真实的键盘输入来处理不需要安装任何额外驱动。相比之下UNO 的 ATmega328P 主板通常使用 CH340 或 ATmega16U2 作为 USB 转串口芯片只能实现串口通信。即使你把 UNO 接到了电脑上操作系统也不会认为你插入了一个键盘。用 UNO 做游戏手柄当然也可以通过串口转发到电脑端程序但那需要写一个 PC 端的中继软件复杂度和实时性都比 HID 方案差。4.2 摇杆映射方向键死区与迟滞的设计最基础的 PC 手柄模式是把 ESpiora 的摇杆映射成键盘的方向键。代码如下#include Esplora.h #include Keyboard.h const int deadZone 80; void setup() { Keyboard.begin(); } void loop() { int x Esplora.readJoystickX(); int y Esplora.readJoystickY(); if (x 512 - deadZone) { Keyboard.press(KEY_LEFT_ARROW); } else { Keyboard.release(KEY_LEFT_ARROW); } if (x 512 deadZone) { Keyboard.press(KEY_RIGHT_ARROW); } else { Keyboard.release(KEY_RIGHT_ARROW); } if (y 512 - deadZone) { Keyboard.press(KEY_UP_ARROW); } else { Keyboard.release(KEY_UP_ARROW); } if (y 512 deadZone) { Keyboard.press(KEY_DOWN_ARROW); } else { Keyboard.release(KEY_DOWN_ARROW); } if (Esplora.readJoystickSwitch() LOW) { Keyboard.press( ); } else { Keyboard.release( ); } delay(20); }这个代码里有两个值得深入解释的地方。第一个是迟滞设计。如果我直接判断if (x 512) pressLeft那么摇杆在中心附近轻微抖动就会导致方向键疯狂触发游戏画面会闪烁。所以我设定了deadZone 80也就是说只有摇杆数值低于 432 时才算推左超过 592 时才算推右中间区域是死区。实际操作中死区大小要根据你的摇杆偏移情况调整80 是我试过的比较适中的值。第二个是Keyboard.press()和Keyboard.release()的配合。在 HID 协议中一个按键被按下的状态会持续到释放为止。用 press/release 成对的方式可以实现按住方向键时持续输入的效果。需要注意的是Keyboard.press()不会自动去抖所以我在循环末尾加了delay(20)。这个延迟太小的话按键事件会比较不稳定太大则会有明显操作延迟感20 毫秒是实测中比较平衡的数值。4.3 可选模式用加速度计控制鼠标摇杆映射方向键适合大多数 2D 游戏但如果你玩的是需要精确指针控制的游戏比如一些网页小游戏、画图工具用加速度计模拟鼠标会更顺手。这个模式的核心代码并不复杂#include Esplora.h #include Mouse.h void setup() { Mouse.begin(); } void loop() { int accelX Esplora.readAccelerometer(X_AXIS); int accelY Esplora.readAccelerometer(Y_AXIS); int moveX map(accelX, -300, 300, -8, 8); int moveY map(accelY, -300, 300, -8, 8); Mouse.move(moveX, moveY, 0); if (Esplora.readJoystickSwitch() LOW) { if (!Mouse.isPressed(MOUSE_LEFT)) { Mouse.press(MOUSE_LEFT); } } else { Mouse.release(MOUSE_LEFT); } delay(15); }Mouse.move()的第三个参数是滚轮传 0 表示不滚动。map()函数把加速度计的原始输出范围映射成鼠标移动的像素增量。这里有一个很关键的使用心得不同 Esplora 板子在水平放置时加速度计读数可能是几十甚至上百不是严格的 0。所以这个 -300 到 300 的映射区间是我这块板子平放时的大致范围你的板子可能不同。正确做法是先烧录一个只输出readAccelerometer()的测试程序把板子水平放在桌上记录三轴读数再根据读数偏差设计映射区间。我每次换一块 Esplora都会重新做一次这个校准操作。4.4 实测操作手感与调整建议把 Esplora 当 PC 手柄使用时我实测过玩网页上的横版跳跃游戏和迷宫游戏。整体手感比用键盘直接玩要自然不少左手握板、右手摇杆的姿势很像掌机。有一个比较好用的改进是把四个板载按键也映射成键盘按钮。比如四个按键分别映射成 1、2、3、4在很多游戏里可以当作技能快捷键。代码里在loop()中读取Esplora.readButton(LEFT_BUTTON)按下时Keyboard.press(1)松开时Keyboard.release(1)。这样虽然每个按键要独立处理但映射逻辑和摇杆一致。我建议你在实际使用前先写一个按键测试程序按下任何一个输入就在串口输出对应状态确保每个键都正常工作这样调试游戏控制时能更快定位问题。因为一旦Keyboard库生效后你在电脑上看到的将是真实的键盘事件如果按键映射错了调试区分输入问题还是逻辑问题会很难。5. 游戏氛围拉满蜂鸣器音效和 RGB 状态灯5.1 用 tone() 做游戏音效不占额外硬件游戏反馈不只是屏幕上的画面变化声音对节奏和情绪的影响比我预想中要大。Esplora 板载蜂鸣器用Esplora.tone(frequency, duration)就能播放音效。我做了一个简单的音效函数每次得分、死亡、开始游戏播放不同的单音序列void playScoreSound() { Esplora.tone(880, 60); delay(70); Esplora.tone(1174, 60); delay(70); Esplora.tone(1567, 80); delay(100); Esplora.noTone(); } void playGameOverSound() { Esplora.tone(400, 150); delay(180); Esplora.tone(300, 150); delay(180); Esplora.tone(200, 300); Esplora.noTone(); }delay()在音效函数里是有意为之目的是让两个音之间有间隔。但把delay()放在游戏主循环里会阻塞画面刷新所以我的做法是只在播放音效时短暂阻塞几毫秒游戏主体循环里用非阻塞的定时器逻辑来控制帧率。有几个音效设计心得得分音的频率应该比游戏音高一些让人有变强的感知死亡音通常是低音、长音让人觉得结束了。频率数值可以直接用标准音高映射——中央 C 是 261.63HzD 是 293.66HzE 是 329.63Hz但蜂鸣器播放超过两个音阶的音符很容易刺耳我一般控制在 200Hz 到 2000Hz 之间。5.2 RGB LED 当血条和状态提示Esplora 上的两颗 RGB LED很适合当游戏里的状态指示。比如在我另一个接水果小游戏里LED 的红色代表剩余生命满血时是绿色生命值减少时向红色渐变。Esplora.writeRGB(红, 绿, 蓝)的参数范围是 0 到 255。生命值变化的代码大概这样int lives 3; int maxLives 3; void updateLED() { int green (lives * 255) / maxLives; int red 255 - green; Esplora.writeRGB(red, green, 0); }这个写法很简单但效果很直观。玩家不用盯着屏幕上方的数字余光扫到 LED 颜色就知道自己还剩多少血。我在一个快节奏游戏里把 LED 改成了闪烁提示当生命值只剩 1 时LED 会以 200 毫秒间隔闪烁红色制造紧迫感。用 Arduino 的millis()做非阻塞计时避免闪烁逻辑阻塞游戏主循环。5.3 麦克风传感器用声音做互动彩蛋Esplora 板载的麦克风很多教程只是用来读取环境音量很少有人把它放进游戏逻辑里。但我觉得这是最有趣的一个输入源。麦克风读取函数是Esplora.readMicrophone()返回环境声音的模拟量声音越大数值越高。我做过一个声控跳跳乐的小实验玩家需要贴近板子吹一口气或者大喊一声角色就会向上跳。核心逻辑是检测音量超过阈值const int voiceThreshold 800; // 需要根据实际环境调整 void loop() { int volume Esplora.readMicrophone(); if (volume voiceThreshold) { // 触发跳跃动作 playerVelocity -5; } // 其他游戏逻辑 }这个阈值需要在游戏开始前做一次环境采集否则在安静环境里会误触发在嘈杂环境里又触发不了。我的做法是程序启动后先读取前 500 毫秒的麦克风平均值把阈值设成平均值 400。这样每次启动都会根据环境自动校准。这里也顺带提一句麦克风读取的波动比较大如果要做精确的音频分析建议用模拟引脚采样但作为游戏彩蛋阈值判断已经足够。6. 调试记录运行 Esplora 项目时踩过的坑6.1 上电后串口不识别驱动版本与数据线的坑这是最频繁出现的问题。我一度以为板子烧了结果换了一根能传输数据的短线就恢复正常。如果你在设备管理器里看不到 COM 口不要急着刷固件先确认数据线是数据线而不是充电线。USB 线这玩意儿外观上完全一样只有试了才知道。另外ATmega32U4 的驱动有时会被 Windows 错误识别为USB 串行设备而不是Arduino Esplora。这种情况下建议在设备管理器里手动更新驱动指定到 Arduino IDE 安装目录下的 drivers 文件夹。如果还不行就试试拔掉所有其他 USB 设备再插 Esplora排除多设备冲突。6.2 摇杆坐标漂移校准阈值不能拍脑袋摇杆读数居中不是绝对 512每块板子都有个体差异。我第一次做贪吃蛇时默认死区是 400 到 600结果有一块板子摇杆居中读数是 580导致不推摇杆时频繁误触发右移。后来我在初始化阶段加了一段自动校准代码程序启动后两秒内玩家不操作摇杆程序读取 20 次取平均值把中心值存到全局变量里。后面判断方向时就以这个中心值为基准。校准代码并不复杂int centerX 512; int centerY 512; void calibrateJoystick() { long sumX 0, sumY 0; for (int i 0; i 20; i) { sumX Esplora.readJoystickX(); sumY Esplora.readJoystickY(); delay(50); } centerX sumX / 20; centerY sumY / 20; }启动时加一句calibrateJoystick()后面判断方向时用x centerX - deadZone这样的写法问题就消失了。6.3 TFT 屏幕白屏库版本冲突Esplora TFT 屏幕连接正常但白屏我遇到过一次。原因是 IDE 里同时存在旧版 TFT 库和新版 TFT 库导致编译时引用了错误版本。解决方法是在项目 - 加载库 - 管理库里卸载多余的 TFT 库版本只保留一个。另外Esplora 的 TFT 屏幕不要接在数字引脚的扩展口上必须用屏幕模块的专用接口否则 SPI 引脚定义会错乱。如果你用的不是官方 TFT 模块而是一块通用型号的 TFT 屏幕情况会复杂很多。不同厂商的 TFT 屏幕驱动芯片差异很大Adafruit 的 ST7735 库可能不兼容需要根据屏幕背面的芯片型号找到对应驱动。我的建议是既然买了 Esplora就尽量用官方 TFT 模块省心。6.4 模拟键盘导致系统失控延时不是越小越好第四个项目里使用 Keyboard 库模拟键盘时我犯过一个比较严重的错误为了降低操作延迟把delay()从 20 毫秒改成了 1 毫秒结果系统开始不连贯地连续输出大量按键事件电脑整个像卡死了一样。原因是 USB HID 的发送速率只有约 1000Hz而且操作系统对按键事件有自己的节流算法过快的连续 press/release 会被系统当成异常输入产生完全不可控的行为。解决办法很简单把delay()保持在 20 毫秒以上。我已经反复测试过不同延时和操作手感的平衡20 毫秒到 30 毫秒是最稳定的区间再小会出问题再大则会感到明显延迟。如果你的游戏对反应速度要求特别高可以考虑把按键输入改成事件驱动而不是轮询但那会显著增加代码复杂度收益并不大。6.5 电池供电不稳定那根线也有讲究Esplora 支持使用电池供电官方规格是 3.7V 锂聚合物电池通过板子上的 JST 接口连接。我在一个移动掌机项目中试过电池供电遇到的问题是电池电压低于 3.7V 后TFT 屏幕会突然花屏或闪屏但板载 LED 还是亮的程序也没死。这是因为屏幕对电压波动比主控更敏感。解决方法是加一个稳压电路或者直接使用 5V 供电的移动电源加一根 USB 线。我的实践是做移动项目时尽量用稳定的 5V 电源做桌面项目时直接用 USB几乎没有必要用电池。如果你一定要用电池建议在程序里用Esplora.readTemperature(DEGREES_C)加光照传感器等手段做个简单电量检测在低电量时亮红灯提示否则屏闪的体验太糟了。Esplora 这个板子论性能不算强论生态也不算广但它是少数几块能让我拿来就玩的 Arduino 板子。它把所有游戏外设需要的输入输出都集成了省掉了接线的繁琐让我能专注于游戏逻辑和交互设计。我在实际做这些项目时最大的体会是用 Esplora 做游戏关键不是堆代码而是把它的输入手感、音效反馈、屏幕逻辑协调好。如果你也有一块 Esplora别让它继续吃灰先跑一个贪吃蛇试试再把键盘模拟接上你会发现这块老板子比想象中好玩多了。