亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

Arduboy Clone 与 Arduino Nano 和 I2C OLED 显示器

组件和用品

Arduino Nano R3
× 1
图形 OLED,128 x 64
× 1
蜂鸣器
× 1
触觉开关,顶部驱动
× 6
RGB 扩散共阴极
× 1
电阻 221 ohm
× 3
电阻 10k ohm
× 1

必要的工具和机器

3D 打印机(通用)
烙铁(通用)

关于这个项目

Arduboy 是一个信用卡大小的微型游戏系统。它安装了经典的 8 位游戏,可以从在线可用的开源游戏库中重新编程。 Arduboy 是开源的,因此您可以学习编码和创建自己的游戏。原始版本基于 ATmega32U4 微控制器和 128x64 Pixels 串行 OLED 显示器。

其结构如下所示的控制台由 Arduino Nano 和 I2C 版本的 OLED 显示器组成,它们可以更容易以更低的价格找到。您可以在以下位置下载必要的库和代码:

https://github.com/harbaum/Arduboy2

如果您拥有 3D 打印机,您还可以下载安装控制台的可能选项的 .STL 文件。同一站点上提供了详细的安装指南。它由 Arduino Nano 和一块 3.7v 的锂离子电池供电,运行良好。

我在这个控制台上测试了很多游戏,所有游戏都很棒:

- ArduBreakout

- 弹球

- 影行者

- 蛇

- 病毒-LQP-79

- 十九43

还有更多……

示意图如下所示。

例如,我将代码提供给 ArduBreakout 游戏,但您可以在 Arduboy 的站点上下载与此版本控制台兼容的任何其他游戏。

代码

  • ArduBreakout 游戏
ArduBreakout GameArduino
/* Breakout 版权所有 (C) 2011 Sebastian Goscik 保留所有权利。 Scott Allen 2016 年的修改(在 ??? 之前的更改之后)这个库是免费软件;您可以根据自由软件基金会发布的 GNU 宽松通用公共许可证的条款重新分发和/或修改它;许可证的 2.1 版,或(由您选择)任何更高版本。 */#include // 阻止 EEPROM 以保存高分#define EE_FILE 2Arduboy2 arduboy;BeepPin1 beep;const unsigned int FRAME_RATE =40; // 每秒帧数const unsigned int COLUMNS =13; //bricksconst unsigned int ROWS =4 的列数; //bricksint dx =-1 的行数; //ballint的初始运动dy =-1; //ballint xb的初始移动; //球开始位置int yb; //球开始位置布尔值释放; //如果球已经被玩家释放boolean paused =false; //如果游戏已经暂停byte xPaddle; //paddleboolean 的 X 位置 isHit[ROWS][COLUMNS]; //如果砖块被击中或notbooleanbounced=false的数组; //用于修复双跳glitchbyte living =3; //生命字节级别的数量=1; //当前级别unsigned int score=0; //为游戏评分unsigned int blocksCount; //砖的数量hitboolean pad, pad2, pad3; //用于停止重复的按钮按下缓冲区boolean oldpad, oldpad2, oldpad3;char text_buffer[16]; //一般字符串bufferboolean start=false; //If in menu or in gameboolean initialDraw=false;//如果初始抽签已经发生char initials[3]; //高分中使用的首字母//碰撞检测中使用的球边界byte leftBall;byte rightBall;byte topBall;byte bottomBall;//碰撞检测中使用的Brick Boundsbyte leftBrick;byte rightBrick;byte topBrick;byte bottomBrick;byte tick;void setup (){ arduboy.begin();哔。开始(); arduboy.setFrameRate(FRAME_RATE); arduboy.initRandomSeed();}void loop(){ // 暂停渲染直到下一帧时间到了 if (!(arduboy.nextFrame())) return; // 处理铃声的定时和停止 beep.timer(); //标题屏幕循环从标题屏幕//和高分切换直到按下FIRE while (!start) { start =titleScreen(); if (!start) { start =displayHighScores(EE_FILE); } } //初始关卡绘制 if (!initialDraw) { //清屏 arduboy.clear(); //Selects Font //绘制新的关卡level =1; newLevel();分数 =0;初始绘制=真; } if (lives>0) { drawPaddle(); //如果按下 FIRE 则暂停游戏 pad =arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON); if(pad ==true &&oldpad ==false &&release) { oldpad2 =false; //强制填充循环2运行一次 pause(); } oldpad =垫;拉球(); if(brickCount ==ROWS * COLUMNS) { level++; newLevel(); } } else { drawGameOver(); if (score> 0) { enterHighScore(EE_FILE); arduboy.clear();初始绘制=假;开始=假;生命=3; newLevel(); } arduboy.display();}void movePaddle(){ //向右移动 if(xPaddle  0) { if (arduboy.pressed(LEFT_BUTTON)) { xPaddle-=2; } }}void moveBall(){ tick++; if(released) { //移动球 if (abs(dx)==2) { xb +=dx/2; // 2x 速度实际上是 1.5 速度 if (tick%2==0) xb +=dx/2; } else { xb +=dx; } yb=yb + dy; //设置边界 leftBall =xb;右球 =xb + 2;顶球 =yb;底球 =yb + 2; //从顶部边缘反弹 if (yb <=0) { yb =2; dy =-dy;播放音(523, 250); } //如果底部边缘被击中则失去生命 if (yb>=64) { arduboy.drawRect(xPaddle, 63, 11, 1, 0); x桨=54; yb=60;释放=假;活着——; playToneTimed(175, 500); if (random(0, 2) ==0) { dx =1; } else { dx =-1; } } //从左侧反弹 if (xb <=0) { xb =2; dx =-dx;播放音(523, 250); } //从右侧反弹 if (xb>=WIDTH - 2) { xb =WIDTH - 4; dx =-dx;播放音(523, 250); } //从桨上反弹 if (xb+1>=xPaddle &&xb<=xPaddle+12 &&yb+2>=63 &&yb<=64) { dy =-dy; dx =((xb-(xPaddle+6))/3); //在球上应用旋转 // 防止直线反弹 if (dx ==0) { dx =(random(0,2) ==1) ? 1:-1; } playTone(200, 250); } //从砖块反弹 for (byte row =0; row =topBrick &&leftBall <=rightBrick &&rightBall>=leftBrick) { Score();砖块数++; isHit[row][column] =true; arduboy.drawRect(10*column, 2+6*row, 8, 4, 0); //垂直碰撞 if (bottomBall> bottomBrick || topBall  rightBrick) { //每个球移动只反弹一次砖块 if(!bounced) { dx =- dx; xb +=dx;反弹 =真;播放音(261, 250); } } } } } } //重置弹跳反弹=false; } else { //球跟随桨 xb=xPaddle + 5; //如果 FIRE 按下则释放球 pad3 =arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON); if (pad3 ==true &&oldpad3 ==false) { 发布 =true; //在球释放时应用随机方向 if (random(0, 2) ==0) { dx =1; } else { dx =-1; } //确保球朝上 dy =-1; } oldpad3 =pad3; }}void drawBall(){ // arduboy.setCursor(0,0); // arduboy.print(arduboy.cpuLoad()); // arduboy.print(" "); arduboy.drawPixel(xb, yb, 0); arduboy.drawPixel(xb+1, yb, 0); arduboy.drawPixel(xb, yb+1, 0); arduboy.drawPixel(xb+1, yb+1, 0);移动球(); arduboy.drawPixel(xb, yb, 1); arduboy.drawPixel(xb+1, yb, 1); arduboy.drawPixel(xb, yb+1, 1); arduboy.drawPixel(xb+1, yb+1, 1);}void drawPaddle(){ arduboy.drawRect(xPaddle, 63, 11, 1, 0);移动桨(); arduboy.drawRect(xPaddle, 63, 11, 1, 1);}void drawGameOver(){ arduboy.drawPixel(xb, yb, 0); arduboy.drawPixel(xb+1, yb, 0); arduboy.drawPixel(xb, yb+1, 0); arduboy.drawPixel(xb+1, yb+1, 0); arduboy.setCursor(37, 42); arduboy.print("游戏结束"); arduboy.setCursor(31, 56); arduboy.print("分数:"); arduboy.print(score); arduboy.display(); arduboy.delayShort(4000);}void pause(){ paused =true; //在屏幕上绘制暂停 arduboy.setCursor(52, 45); arduboy.print("暂停"); arduboy.display();而(暂停){ arduboy.delayShort(150); //如果按下 FIRE 则取消暂停 pad2 =arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON); if (pad2 ==true &&oldpad2 ==false &&发布) { arduboy.fillRect(52, 45, 30, 11, 0);暂停=假; } oldpad2 =pad2; }}void Score(){ score +=(level*10);}void newLevel(){ //展开桨 arduboy.drawRect(xPaddle, 63, 11, 1, 0); //取消绘制球 arduboy.drawPixel(xb, yb, 0); arduboy.drawPixel(xb+1, yb, 0); arduboy.drawPixel(xb, yb+1, 0); arduboy.drawPixel(xb+1, yb+1, 0); //改变各种变量来重置游戏 xPaddle =54; yb =60;砖计数 =0;释放=假; //绘制新砖并重置它们的值 for (byte row =0; row <4; row++) { for (byte column =0; column <13; column++) { isHit[row][column] =false; arduboy.drawRect(10*column, 2+6*row, 8, 4, 1); } } arduboy.display();}//用于在读取按钮时延迟图像 inputboolean pollFireButton(int n){ for(int i =0; i  0) { sprintf(text_buffer, "%c%c%c %u", initials[0], initials[1], initials[2], score); arduboy.setCursor(x + 24, y + (i*8)); arduboy.print(text_buffer); arduboy.display(); } } if (pollFireButton(300)) { return true;返回假; arduboy.display();}boolean titleScreen(){ //清屏 arduboy.clear(); arduboy.setCursor(16,22); arduboy.setTextSize(2); arduboy.print("突破"); arduboy.setTextSize(1); arduboy.display();如果(pollFireButton(25)){ 返回真; } //Flash "Press FIRE" 5 次 for(byte i =0; i <5; i++) { //绘制 "Press FIRE" arduboy.setCursor(31, 53); arduboy.print("按火!"); arduboy.display();如果(pollFireButton(50)){ 返回真; } //移除“Press FIRE” arduboy.setCursor(31, 53); arduboy.print(" "); arduboy.display();如果(pollFireButton(25)){ 返回真; } } return false;}//通过益智设计添加高分的函数void enterInitials(){ byte index =0; arduboy.clear();首字母[0] =' ';首字母 [1] =' ';首字母 [2] =' '; while (true) { arduboy.display(); arduboy.clear(); arduboy.setCursor(16,0); arduboy.print("高分"); sprintf(text_buffer, "%u", score); arduboy.setCursor(88, 0); arduboy.print(text_buffer); arduboy.setCursor(56, 20); arduboy.print(姓名首字母[0]); arduboy.setCursor(64, 20); arduboy.print(首字母[1]); arduboy.setCursor(72, 20); arduboy.print(首字母[2]); for(byte i =0; i <3; i++) { arduboy.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, 1); } arduboy.drawLine(56, 28, 88, 28, 0); arduboy.drawLine(56 + (index*8), 28, 56 + (index*8) + 6, 28, 1); arduboy.delayShort(70); if (arduboy.pressed(LEFT_BUTTON) || arduboy.pressed(B_BUTTON)) { if (index> 0) { index--; playToneTimed(1046, 80); } } if (arduboy.pressed(RIGHT_BUTTON)) { if (index <2) { index++; playToneTimed(1046, 80); } } if (arduboy.pressed(UP_BUTTON)) { initials[index]++; playToneTimed(523, 80); // A-Z 0-9 :-? !-/ ' ' if (initials[index] =='0') { initials[index] =' '; } if (initials[index] =='!') { initials[index] ='A'; } if (initials[index] =='[') { initials[index] ='0'; } if (initials[index] =='@') { initials[index] ='!'; } } if (arduboy.pressed(DOWN_BUTTON)) { initials[index]--; playToneTimed(523, 80); if (initials[index] ==' ') { initials[index] ='?'; } if (initials[index] =='/') { initials[index] ='Z'; } if (initials[index] ==31) { initials[index] ='/'; } if (initials[index] =='@') { initials[index] =' '; } } if (arduboy.pressed(A_BUTTON)) { playToneTimed(1046, 80);如果(索引 <2){ 索引++; }其他{返回; } } }}void enterHighScore(byte file){ // EEPROM的每一块有7个高分,每个高分条目 // 5个字节长:3个字节的首字母和2个字节的score。 int 地址 =文件 * 7 * 5 + EEPROM_STORAGE_SPACE_START;字节嗨,洛;字符 tmpInitials[3];无符号整数 tmpScore =0; // 高分处理 for(byte i =0; i <7; i++) { hi =EEPROM.read(address + (5*i)); lo =EEPROM.read(地址 + (5*i) + 1); if ((hi ==0xFF) &&(lo ==0xFF)) { // 值未初始化,因此将此条目 // 视为 0 分。tmpScore =0; } else { tmpScore =(hi <<8) |哦; } if (score> tmpScore) { enterInitials(); for(byte j =i; j <7; j++) { hi =EEPROM.read(address + (5*j)); lo =EEPROM.read(地址 + (5*j) + 1); if ((hi ==0xFF) &&(lo ==0xFF)) { tmpScore =0; } else { tmpScore =(hi <<8) |哦; } tmpInitials[0] =(char)EEPROM.read(address + (5*j) + 2); tmpInitials[1] =(char)EEPROM.read(address + (5*j) + 3); tmpInitials[2] =(char)EEPROM.read(address + (5*j) + 4); // 将分数和首字母写入当前插槽 EEPROM.update(address + (5*j), ((score>> 8) &0xFF)); EEPROM.update(address + (5*j) + 1, (score &0xFF)); EEPROM.update(address + (5*j) + 2, initials[0]); EEPROM.update(address + (5*j) + 3, initials[1]); EEPROM.update(address + (5*j) + 4, initials[2]); // tmpScore 和 tmpInitials 现在保存我们想要在下一个插槽中写入的内容。分数 =tmpScore;首字母[0] =tmp首字母[0];首字母[1] =tmp首字母[1];首字母[2] =tmp首字母[2]; } 分数 =0;首字母[0] =' ';首字母 [1] =' ';首字母 [2] =' ';返回; } }}// 在指定的持续时间内以指定的频率播放一个音调。void playTone(unsigned int frequency, unsigned int duration){ beep.tone(beep.freq(frequency), duration / (1000 / FRAME_RATE));} // 在指定的持续时间内以指定的频率播放音调,使用 // 延迟音调计时。// 在没有调用 beep.timer() 时使用。void playToneTimed(unsigned int frequency, unsigned int duration){ beep.tone(beep.freq(频率)); arduboy.delayShort(持续时间); beep.noTone();}

定制零件和外壳

3d_parts_ThLGvJvWga.rar

示意图


制造工艺

  1. Arduino I2C 与 Raspi 2 WIOT 的通信
  2. 掌上游戏机 | Arduboy 克隆
  3. Arduino Pong Game - OLED 显示器
  4. Arduino 温度。使用 3.2 显示的监视器和实时时钟
  5. 带有 Arduino 的简单障碍物传感器
  6. 玩 Nextion Display
  7. Arduino Nano:使用操纵杆控制 2 个步进电机
  8. DIY 电压表与 Arduino 和诺基亚 5110 显示器
  9. 基于 Arduino 和 OLED 的元胞自动机
  10. 带有 Arduino Nano 的手持盖革计数器
  11. 带 GPS 和 TFT 显示屏蔽的 GPS 位置显示
  12. Arduino 的隔离模拟输入