Arduino双机交互:光敏电阻与伺服电机实现自动化游戏操控
1. 项目概述:当硬件开始“对话”
如果你玩过Chrome浏览器在断网时出现的那个小恐龙跳跃游戏,并且对Arduino这类开源硬件有点兴趣,那你可能想过:能不能让机器自己玩这个游戏?更进一步,如果让一块Arduino板子运行游戏,另一块板子来“看”着屏幕并自动操控,会是什么景象?这听起来像是个极客的玩笑,但它恰恰是一个绝佳的嵌入式系统入门项目,完美诠释了微控制器(MCU)如何作为“大脑”,协调“眼睛”(传感器)和“手”(执行器)来完成一个具体的自动化任务。
这个项目的核心,就是构建两套独立的Arduino系统,让它们进行一场跨越物理空间的“对话”。系统A负责游戏逻辑的呈现,它将经典的Chrome恐龙游戏简化后,运行在一块搭载了LCD按键盾板的Arduino Uno上。系统B则扮演“玩家”的角色,其核心是一个 光敏电阻(LDR) ,它紧贴在系统A的LCD屏幕特定位置,充当“视觉”传感器,实时检测屏幕上是否有障碍物(仙人掌)经过。一旦检测到信号,系统B的“大脑”(另一块Arduino Uno)会立刻做出决策,驱动一只 微型伺服电机(Servo) 的摆臂轻轻按下系统A盾板上的跳跃按键。整个过程,“感知-决策-执行”的自动化闭环清晰可见。
这不仅仅是让恐龙自动跳跃那么简单。对于初学者,你能亲手实践数字/模拟信号读取、阈值判断、伺服电机控制等基础技能。对于有经验的开发者,它涉及了系统间无通信协议的交互设计、传感器抗干扰校准、实时性考量等更深层的问题。无论是用于教学演示、自动化测试原型,还是单纯作为一个有趣的创意项目,它都能让你对硬件编程和系统集成有更直观、更深刻的理解。接下来,我将拆解这个项目的每一个环节,从设计思路到代码细节,从硬件连接到调试技巧,分享我在实现过程中积累的所有经验。
2. 系统设计与核心思路拆解
在开始焊接任何一根线之前,理清整个系统的设计思路至关重要。这个项目可以清晰地划分为两个子系统:游戏运行端(Dino Game Unit)和游戏操控端(Player Unit)。它们之间没有使用任何有线(如I2C、UART)或无线(如蓝牙、Wi-Fi)的通信协议,而是通过“光”这种物理媒介进行单向、间接的交互。这种设计选择背后有它的巧妙之处和局限性,值得我们深入探讨。
2.1 为何选择“光信号”作为交互媒介?
最直接的想法可能是用杜邦线直接连接两块Arduino的IO口,或者用串口发送指令。但本项目采用了更“物理”的方式:用光敏电阻(LDR)读取LCD屏幕的亮度变化。这主要基于以下几点考量:
- 解耦与简化 :两块Arduino完全独立供电、独立编程。你不需要处理复杂的通信协议(如定义数据包格式、处理通信错误、同步双方状态),大大降低了软件复杂度和调试难度。系统B完全通过“观察”系统A的输出(屏幕图像)来行动,这是一种典型的“传感器-环境”交互模式。
- 非侵入式 :这种方式不需要对游戏运行端(系统A)的硬件或代码进行任何修改以适配通信功能。游戏代码可以保持其独立性和完整性,就像在单独运行一样。这符合模块化设计思想,每个子系统功能内聚。
- 教学价值 :它生动地展示了传感器如何从物理世界(这里是光信号)获取信息。LDR检测亮度变化是一个经典的模拟输入案例,比直接读取一个数字信号更能让人理解模数转换(ADC)和阈值判定的意义。
当然,这种方式也有其局限性,主要是抗干扰能力较弱(环境光变化会影响LDR),以及信息带宽极低(只能传递“有/无”障碍物这种简单信息)。但对于“检测固定位置、固定颜色的障碍物”这个特定任务,它足够简单有效。
2.2 双系统硬件架构解析
让我们从硬件角度俯瞰整个系统:
系统A:游戏运行端
- 核心控制器 :Arduino Uno。选择Uno是因为其资源(内存、IO)足以运行一个简化版的图形游戏,且生态丰富,兼容性好。
- 人机交互界面 :LCD按键盾板。这块盾板直接插在Uno上,提供了16x2字符的液晶显示屏和五个独立按键(包括我们需要的“跳跃”键)。它解决了显示和输入的问题,无需额外布线,非常整洁。
- 功能 :运行一个用Arduino代码重写的简化版恐龙游戏。恐龙自动向前跑,屏幕上有随机生成的障碍物(用字符模拟的仙人掌)。当玩家(或我们的系统B)按下盾板上的“选择”键(通常映射为跳跃功能)时,恐龙跳跃。
系统B:游戏操控端
- 核心控制器 :另一块Arduino Uno。
- 感知单元 :光敏电阻(LDR)与一个固定电阻(如10kΩ)组成分压电路,连接到模拟输入引脚(如A0)。LDR被物理固定在系统A的LCD屏幕正前方。
- 决策与执行单元 :Arduino读取LDR的模拟值,通过阈值判断逻辑决定是否“跳跃”。若判定跳跃,则驱动一个微型伺服电机(如SG90),电机的摆臂被机械定位在系统A盾板的跳跃按键上方。
- 辅助单元 :最初可能包含一个LED作为触发指示灯,但实际中发现其光线会干扰旁边的LDR,故在最终设计中通常移除或仅在调试时使用。
两个系统通过“光”连接:系统A的屏幕显示特定的像素变化(仙人掌经过) -> 系统B的LDR感知到该点的亮度变化 -> 系统B的Arduino处理信号并触发伺服电机 -> 伺服电机按下系统A的按键。这个闭环就是整个项目的灵魂。
3. 硬件准备与连接细节
工欲善其事,必先利其器。正确的硬件选型和可靠的连接是项目成功的基石。这里我会列出详细的物料清单,并解释关键元器件的选型原因,然后给出清晰的接线图与焊接建议。
3.1 物料清单与选型考量
系统A(游戏运行端):
- Arduino Uno R3(1个) :项目基石。不建议用更便宜的板子(如Nano)直接替代盾板,因为引脚布局和物理尺寸可能不兼容。
- 1602 LCD按键盾板(1个) :这是关键部件。务必确认是兼容Arduino Uno的“按键盾板”(Keypad Shield),它通常集成有LCD(16字符x2行)、背光、一个电位器(调节对比度)以及5个按键(上、下、左、右、选择)。我们主要利用其LCD和“选择”键。
系统B(游戏操控端):
- Arduino Uno R3(1个) :另一块Uno。
- 微型伺服电机 SG90(1个) :选择SG90是因为它体积小、扭矩足够按下按键、价格低廉且控制简单(标准PWM信号)。舵机内部包含电机、减速齿轮组和反馈电路,可以精确控制角度。
- 光敏电阻 GL5528(1个) :这是一种常用的硫化镉(CdS)光敏电阻,电阻值随光照增强而减小。选择它是因为其灵敏度适中,响应速度对于本项目(几十毫秒级)绰绰有余。
- 10kΩ 直插电阻(1个) :用于与LDR组成分压电路。10kΩ是一个与LDR在室内光照下阻值范围匹配良好的值,能产生变化范围较大的分压信号。
- 杜邦线(公对公、公对母若干) :用于连接。
- 小型面包板(1个) :用于快速搭建和测试电路,后期可焊接。
- (可选)LED及220Ω限流电阻 :用于初期调试指示,正式运行建议移除以防光干扰。
注意:关于电源 两个Arduino最好分别使用独立的5V/1A以上的USB电源适配器供电。���果共用一个电源,要确保其电流输出能力足够(>2A),并注意共地问题。伺服电机在动作瞬间电流可能达到500mA,若与Arduino共用电脑USB口供电,可能导致电脑USB端口保护或板子复位。
3.2 电路连接详解与焊接建议
系统A的连接最简单 :只需将LCD按键盾板直接插在Arduino Uno的引脚排母上,确保方向正确(通常盾板的引脚排针与Uno的排母完全对应)。插紧即可,无需焊接。
系统B的电路搭建是重点 ,原理图如下:
系统B (Player Arduino Uno)
---------------------------------
模拟引脚 A0 ---[LDR]--- 5V
|
[10kΩ Resistor]
|
GND
---------------------------------
数字引脚 9 (PWM) --- 伺服电机信号线(橙色/白色)
5V --- 伺服电机电源线(红色)
GND --- 伺服电机地线(棕色/黑色)
---------------------------------
(可选)数字引脚 13 --- LED(+) --- [220Ω] --- GND
分压电路原理 :LDR和10kΩ电阻串联在5V和GND之间,它们的连接点接到A0。当光照强时,LDR电阻变小,A0点的电压(相对于GND)升高;光照弱时,LDR电阻变大,A0点电压降低。Arduino的ADC(模数转换器)将这个0-5V的电压转换为0-1023的整数值。
伺服电机连接 :SG90有三根线。 红色(正极)接5V , 棕色或黑色(负极)接GND , 橙色或白色(信号线)接一个支持PWM的数字引脚(如9号) 。PWM(脉冲宽度调制)信号用于控制舵机角度。
焊接建议 : 为了系统稳定和美观,建议在面包板测试无误后,将系统B的核心电路(LDR、电阻、伺服电机的信号线)焊接在一块洞洞板(万用板)上,并使用排针或排母与Arduino连接。对于LDR,可以焊接两根较长的导线(建议使用不同颜色的排线),以便将其引到系统A的屏幕前固定。伺服电机也可以焊接杜邦线母头,方便插拔。 焊接时务必注意烙铁温度和时间,避免烫坏光敏电阻或伺服电机的塑料部件。
4. 软件实现:代码逐行解析与优化
硬件就绪后,赋予它们“智能”的代码就是灵魂。本项目有两份独立的Arduino草图(Sketch),我们将逐一深入分析,并分享关键的调试技巧和优化空间。
4.1 系统A:恐龙游戏代码剖析
系统A的代码核心是在LCD上模拟一个横向卷轴的恐龙游戏。由于1602液晶是字符型,无法显示精细图像,所以我们需要用自定义字符(Custom Character)来构建恐龙和仙人掌的图形。
核心逻辑流程:
- 初始化 :设置LCD,创建恐龙、仙人掌等自定义字符图形。
- 游戏循环 : a. 检测按键(来自盾板或系统B的物理按压)。如果“选择”键被按下,设置恐龙为“跳跃”状态。 b. 根据恐龙是否处于跳跃状态,计算其垂直位置(Y坐标)。 c. 在屏幕缓冲区(一个逻辑上的数组)中移动障碍物(仙人掌)向左。 d. 随机生成新的障碍物。 e. 检测碰撞:如果恐龙图形与障碍物图形在屏幕缓冲区中的位置重叠,则游戏结束。 f. 将屏幕缓冲区的数据渲染到LCD的特定位置。 g. 延迟一定时间(如60-100毫秒),控制游戏帧率。
关键代码片段与解释:
#include <LiquidCrystal.h> // 使用Arduino自带的液晶库
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // 初始化液晶对象,引脚定义需匹配你的盾板
// 自定义字符数组,用于绘制恐龙和仙人掌
byte dinoChar[8] = { ... }; // 恐龙的位图数据
byte cactusChar[8] = { ... }; // 仙人掌的位图数据
bool isJumping = false;
int dinoY = 0; // 恐龙垂直位置,0表示地面
int jumpHeight = 2; // 最大跳跃高度(字符行数)
int jumpCounter = 0;
void setup() {
lcd.begin(16, 2); // 初始化16x2 LCD
lcd.createChar(0, dinoChar); // 将自定义字符存入LCD的CGRAM
lcd.createChar(1, cactusChar);
// ... 其他初始化
}
void loop() {
// 1. 检测跳跃按键(按键盾板的‘选择’键通常连接到模拟引脚A0,通过读取特定电压值判断)
int key = analogRead(A0);
if (key < 100) { // 根据你的盾板文档,这个阈值可能不同,常见值:选择键~50
isJumping = true;
jumpCounter = 0;
}
// 2. 更新恐龙跳跃状态
if (isJumping) {
dinoY = jumpPattern[jumpCounter]; // 使用一个预定义的数组来控制跳跃轨迹(抛物线)
jumpCounter++;
if (jumpCounter >= sizeof(jumpPattern)) {
isJumping = false;
dinoY = 0;
}
}
// 3. 更新障碍物位置(向左移动)
// 4. 碰撞检测
// 5. 渲染到LCD
// ...
delay(80); // 控制游戏速度
}
实操心得:LCD盾板按键读取 不同厂商的LCD按键盾板,其按键的模拟电压值可能略有差异。最可靠的方法是先在
setup()里写一个简单的循环,打印出analogRead(A0)的值,然后分别按下每个键,记录下对应的数值范围。通常“选择”键的值最小(最接近0),“右”键最大(接近1023)。用这些实测值作为判断阈值,比用网上找的固定值更可靠。
4.2 系统B:玩家控制代码精讲
系统B的代码相对简单,但更注重稳定性和抗干扰。其核心是一个状态机,不断读取环境光强,判断是否有“事件”发生。
核心逻辑流程:
- 初始化 :配置伺服电机引脚,将其移动到初始(未按下按键)位置。初始化串口(用于调试,输出光敏值)。
- 主循环 : a. 读取LDR连接的模拟引脚(如A0)的值。 b. 对读取的值进行简单的软件滤波(例如,取最近几次读数的平均值),以减少噪声波动。 c. 将滤波后的值与一个预设的“触发阈值”进行比较。 d. 如果光值 高于 阈值(说明屏幕对应位置变亮,可能是仙人掌的白色背景或仙人掌本身经过),且当前不处于触发冷却期,则触发跳跃动作。 e. 触发动作:快速驱动伺服电机到一个角度,模拟按下按键,然后迅速返回原位。同时,进入一个短暂的“冷却期”(例如200毫秒),防止单次障碍物触发多次跳跃。 f. 如果光值低于阈值,则维持待机状态。
关键代码片段与解释:
#include <Servo.h> // 使用Arduino自带的舵机库
Servo myServo;
const int ldrPin = A0;
const int servoPin = 9;
const int threshold = 700; // 触发阈值,需要根据实际环境校准!
const unsigned long cooldownTime = 200; // 冷却时间,单位毫秒
int ldrValue = 0;
int filteredValue = 0;
unsigned long lastTriggerTime = 0;
bool isInCooldown = false;
void setup() {
Serial.begin(9600); // 初始化串口,用于调试输出光敏值
myServo.attach(servoPin);
myServo.write(85); // 初始角度,确保摆臂不触碰按键
delay(1000);
}
void loop() {
// 1. 读取并滤波
ldrValue = analogRead(ldrPin);
// 简单移动平均滤波
filteredValue = (filteredValue * 0.7) + (ldrValue * 0.3);
// 2. 检查冷却状态
if (isInCooldown) {
if (millis() - lastTriggerTime > cooldownTime) {
isInCooldown = false;
}
}
// 3. 阈值判断与触发
if (!isInCooldown && filteredValue > threshold) {
triggerJump();
lastTriggerTime = millis();
isInCooldown = true;
}
// (��选)串口输出调试信息
Serial.print("Raw:");
Serial.print(ldrValue);
Serial.print(" Filtered:");
Serial.print(filteredValue);
Serial.print(" Threshold:");
Serial.println(threshold);
delay(10); // 短暂延迟,控制采样率
}
void triggerJump() {
myServo.write(95); // 按下按键的角度,需要根据机械结构微调
delay(50); // 保持按下状态一小段时间
myServo.write(85); // 返回初始角度
}
注意事项:阈值校准是成败关键
threshold这个值不是固定的。它取决于你的LDR型号、与屏幕的距离、屏幕亮度、环境光等因素。 务必进行校准 :将系统全部搭建好,在游戏运行时,打开串口监视器,观察当仙人掌经过LDR检测点时,filteredValue的读数是多少。将这个值减去一个安全余量(比如20-50),作为你的触发阈值。环境光变化(如开关灯)会严重影响这个值,因此最好在光线稳定的环境下运行。
5. 机械组装、校准与系统联调
代码烧录完毕,硬件连接无误,接下来就是最考验动手能力和耐心的环节——机械组装与系统联调。这部分工作决定了你的“机器人玩家”是反应敏捷还是呆若木鸡。
5.1 LDR与伺服电机的定位与固定
LDR(光敏电阻)的定位:
- 确定检测点 :在系统A的LCD屏幕上运行游戏,观察仙人掌出现的位置。仙人掌通常从屏幕右侧出现,向左移动。你需要找一个固定的、仙人掌必定会经过的“检测线”。通常选择屏幕底部一行(第二行)靠左的某个字符位置,比如第7个字符(从0开始计数是第6个)。因为恐龙在底部,仙人掌也出现在底部。
- 固定LDR :将LDR用热熔胶或蓝丁胶小心地固定在屏幕正前方,对准你选定的检测点。 关键是要让LDR的感光面尽可能贴近LCD表面 ,以减少环境光的干扰,同时又要避免用力挤压导致屏幕损坏。可以使用一小块黑色海绵或橡皮泥制作一个遮光罩,套在LDR周围,进一步隔绝侧面环境光。
- 连接 :将LDR的两根长导线连接到系统B的电路上。
伺服电机(Servo)的定位与安装:
- 确定按压点 :找到LCD按键盾板上用于跳跃的“选择”键。
- 制作摆臂 :SG90通常附带多个塑料摆臂。选择一个合适的,或者用轻质材料(如冰棍棒)自制一个。摆臂末端需要粘贴一个柔软、有弹性的触头(如一小块硅胶或海绵),以避免硬接触损坏按键,也能保证按压可靠。
- 固定舵机 :你需要用积木、乐高件、3D打印的支架或者直接用扎带和热熔胶,将舵机牢固地固定在盾板按键的正上方。确保舵机在初始位置(
write(85))时,摆臂触头刚好轻微离开按键表面或刚好接触但未下压;在触发位置(write(95))时,能明显将按键按下一定行程(通常1-2毫米足够)。 - 角度校准 :在代码中,
triggerJump()函数里的myServo.write(95);和myServo.write(85);这两个角度值需要根据你的机械安装实际情况进行微调。通过串口发送命令或修改代码反复测试,找到能可靠触发按键又不使舵机堵转(过度用力)的角度。
5.2 系统联调与性能优化
当两个系统物理上组装在一起后,按以下步骤进行联调:
- 独立测试 :先分别给两个系统上电。系统A应能正常显示并运行恐龙游戏,手动按下盾板按键恐龙应能跳跃。系统B的舵机应能归位到初始角度,打开串口监视器应能看到不断输出的光敏值。
- 阈值精细校准 :
- 启动系统A的游戏,让恐龙跑起来。
- 观察系统B的串口输出,记录下 没有仙人掌 经过检测点时的
filteredValue(基线值)。 - 记录下 有仙人掌 经过检测点时的
filteredValue(峰值值)。 - 将触发阈值设置为:
阈值 = 基线值 + (峰值值 - 基线值) * 0.6。这个0.6的比例因子可以调整,值越大越不易误触发(防环境光突变),但也要保证能检测到仙人掌。
- 触发时机调试 :观察恐龙跳跃时机。理想情况是仙人掌前端到达恐龙位置时,恐龙刚好跳起。如果跳早了,可以尝试稍微增加
cooldownTime或在检测逻辑中加入更复杂的判断(比如需要光值持续高过阈值一段时间)。如果跳晚了,可能是LDR反应慢或机械动作延迟,可以尝试减小cooldownTime,或者优化舵机动作速度(但注意速度太快可能按不稳)。 - 抗干扰优化 :
- 软件滤波 :上文代码中的
filteredValue = (filteredValue * 0.7) + (ldrValue * 0.3);是一种一阶低通滤波,能平滑掉突然的噪声。你可以调整系数(0.7和0.3相加为1),系数越大,滤波效果越强,但响应也越慢。 - 环境光稳定 :尽量在室内光线稳定的环境下运行。避免阳光直射或灯光闪烁(如某些LED灯)的环境。
- 物理遮光 :重申LDR的遮光罩非常重要。
- 软件滤波 :上文代码中的
6. 常见问题排查与进阶玩法
即使按照步骤操作,你也可能会遇到一些“坑”。这里汇总了一些常见问题及其解决方法,并分享一些让这个项目更有趣的扩展思路。
6.1 故障排查速查表
| 现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 系统A游戏无显示 | 1. 盾板接触不良 2. 对比度调节不当 3. 代码引脚定义错误 |
1. 重新插拔LCD盾板,确保所有引脚接触良好。 2. 调节盾板上的蓝色电位器(对比度调节),直到屏幕出现字符。 3. 检查代码中 LiquidCrystal lcd(8,9,4,5,6,7); 这行,确保与你盾板的引脚定义一致(有些盾板是 (8,9,4,5,6,7) ,有些是别的)。 |
| 系统B舵机不转动或乱转 | 1. 电源功率不足 2. 信号线连接错误 3. 代码中舵机对象未绑定(attach) |
1. 使用独立电源为Arduino供电,或确保USB电源适配器能提供足够电流(>1A)。 2. 确认舵机信号线(黄/白)接在了PWM引脚(如9),红线接5V,棕/黑线接GND。 3. 检查 setup() 中是否有 myServo.attach(servoPin); 语句。 |
| LDR读数无变化或变化很小 | 1. LDR或电阻接错 2. LDR距离屏幕太远 3. 屏幕亮度太低或检测点不对 |
1. 用万用表检查分压电路,确认A0引脚电压随遮挡LDR而变化。 2. 将LDR尽可能贴近LCD屏幕表面。 3. 调高LCD背光亮度(如果盾板支持),并确认LDR对准了游戏中仙人掌必经的像素列。 |
| 恐龙总是提前跳或跳得太晚 | 1. 触发阈值设置不当 2. LDR检测点位置不对 3. 舵机响应有延迟 |
1. 重新进行阈值校准,方法见第5.2节。 2. 调整LDR在屏幕前的左右位置,找到最佳的触发点。 3. 检查舵机动作是否顺畅,减少 triggerJump() 函数中的 delay ,但需保证按键能被按下。 |
| 系统B误触发(无仙人掌也跳) | 1. 环境光突变(如人影掠过) 2. 滤波系数太小,噪声大 3. 阈值设置过低 |
1. 加强LDR的物理遮光。 2. 增大滤波公式中的历史值权重(如从0.7改为0.8)。 3. 适当提高触发阈值。 |
| 游戏运行卡顿 | 1. 系统A游戏循环 delay 时间太短,刷新过快 2. 系统B循环中调试输出(Serial.print)过多 |
1. 适当增加系统A主循环中的 delay 值(如从80ms增加到100ms)。 2. 在系统B代码中注释掉或减少 Serial.print 语句,串口输出会占用大量时间。 |
6.2 项目扩展与进阶思路
当基础版本成功运行后,你可以尝试以下扩展,让项目更具挑战性和学习价值:
- 多障碍物识别与策略优化 :原版游戏有仙人掌和飞鸟两种障碍。你可以尝试在屏幕不同高度放置两个LDR,分别检测低处和高处的障碍。系统B的代码需要升级,根据哪个LDR被触发以及恐龙当前状态(是否在跳跃)来决定是跳还是蹲下(映射到另一个按键)。这引入了简单的状态判断逻辑。
- 引入通信协议 :放弃光信号,改用串口(UART)通信。系统A在生成障碍物时,通过TX引脚发送一个简单的字符指令(如‘C’代表仙人掌)给系统B的RX引脚。系统B收到指令后触发跳跃。这能实现更精确、抗干扰的同步,让你学习到基本的串口通信知识。
- 性能统计与显示 :在系统B上增加一个OLED小屏幕,实时显示游戏得分、跳跃次数、成功率等统计信息。这需要学习I2C通信和OLED库的使用。
- 机器学习“调参” :将阈值、滤波系数、冷却时间等参数设置为变量,编写一个简单的算法,让系统在运行过程中根据跳跃成功率(可通过检测游戏是否结束来间接判断)自动微调这些参数,模拟一个简单的自适应过程。
- 硬件升级 :用摄像头模块(如OV7670)替代LDR,结合简单的图像处理(在更强大的板子如Raspberry Pi或ESP32-CAM上),实现真正的视觉识别。这是从“模拟信号处理”到“数字图像处理”的巨大飞跃。
这个项目从构思到实现,充满了硬件交互的乐趣。它像一座桥梁,连接了虚拟的游戏世界和真实的物理操作。每一次调试,每一次校准,都是对“感知-决策-执行”这一自动化核心概念的亲手实践。当你看到伺服电机精准地按下按键,恐龙灵巧地跃过障碍时,那种成就感远超单纯玩一款游戏。希望这份详细的指南能帮你顺利搭建起自己的“Arduino双机游戏系统”,并在此基础上探索出更多可能。
更多推荐



所有评论(0)