산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

Arduboy Clone with Arduino Nano 및 I2C OLED display

구성품 및 소모품

Arduino Nano R3
× 1
그래픽 OLED, 128 x 64
× 1
부저
× 1
촉각 스위치, 상단 작동
× 6
RGB 확산 공통 음극
× 1
저항 221옴
× 3
저항 10k 옴
× 1

필요한 도구 및 기계

3D 프린터(일반)
납땜 인두(일반)

이 프로젝트 정보

Arduboy는 신용 카드 크기의 미니어처 게임 시스템입니다. 클래식 8비트 게임과 함께 설치되며 온라인에서 사용할 수 있는 오픈 소스 게임 라이브러리에서 다시 프로그래밍할 수 있습니다. Arduboy는 오픈 소스이므로 코딩을 배우고 자신만의 게임을 만들 수 있습니다. 원래 버전은 ATmega32U4 마이크로컨트롤러 및 128x64 픽셀 직렬 OLED 디스플레이를 기반으로 합니다.

아래와 같이 구성한 콘솔은 아두이노 나노와 I2C 버전의 OLED 디스플레이로 구성되어 있어 훨씬 저렴한 가격에 쉽게 찾을 수 있습니다. 다음에서 필요한 라이브러리와 코드를 다운로드할 수 있습니다.

https://github.com/harbaum/Arduboy2

3D 프린터를 소유하고 있다면 콘솔이 설치된 가능한 박스 옵션의 .STL 파일을 다운로드할 수도 있습니다. 자세한 설치 가이드는 같은 사이트에서 사용할 수 있습니다. 3.7v의 리튬 이온 배터리 1개가 있는 Arduino Nano로 구동되며 꽤 잘 작동합니다.

이 콘솔에서 많은 게임을 테스트했는데 모두 훌륭하게 작동합니다.

- 아두브레이크아웃

- 핀볼

- 섀도우 러너

- 뱀

- 바이러스-LQP-79

- 나인틴43

그리고 더 많은...

개략도는 아래와 같습니다.

예를 들어 ArduBreakout 게임에 코드를 제공하고 있지만 이 버전의 콘솔과 호환되는 Arduboy 사이트에서 다른 게임을 다운로드할 수 있습니다.

<섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

코드

<울>
  • ArduBreakout 게임
  • ArduBreakout 게임Arduino
    /* Breakout Copyright (C) 2011 Sebastian Goscik All rights reserved. Scott Allen 2016의 수정 사항(???에 의한 이전 변경 이후) 이 라이브러리는 자유 소프트웨어입니다. 자유 소프트웨어 재단(Free Software Foundation)에서 발행한 GNU 약소 일반 공중 라이선스(GNU Lesser General Public License) 조건에 따라 이를 재배포 및/또는 수정할 수 있습니다. 라이선스 버전 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; // 시작 위치 불린 공이 해제됨; //플레이어가 공을 놓으면 paused =false; //게임이 일시 중지된 경우byte xPaddle; // paddleboolean의 X 위치 isHit[ROWS][COLUMNS]; //벽돌이 맞았는지 또는 notboolean bounded=false인 경우의 배열; //이중 바운스를 수정하는 데 사용 glitchbyte lives =3; //livebyte의 양 =1; //현재 레벨unsigned int score=0; // 게임에 대한 점수 unsigned int brickCount; // 벽돌의 양 hitboolean pad, pad2, pad3; //버튼 누름 버퍼 반복 일시 중지 반복 부울 oldpad, oldpad2, oldpad3;char text_buffer[16]; //일반 문자열 버퍼부울 start=false; //메뉴 또는 게임에 있는 경우 initialDraw=false;//초기 추첨이 발생한 경우char initials[3]; //높은 점수에 사용된 이니셜 //충돌 감지에 사용된 볼 경계byte leftBall;byte rightBall;byte topBall;byte bottomBall;//충돌 감지에 사용되는 벽돌 경계byte leftBrick;byte rightBrick;byte topBrick;byte bottomBrick;byte tick;void 설정 (){ arduboy.begin(); beep.begin(); 아두보이.setFrameRate(FRAME_RATE); arduboy.initRandomSeed();}void loop(){ // 다음 프레임 시간이 될 때까지 렌더링을 일시 중지합니다. if (!(arduboy.nextFrame())) return; // 톤의 타이밍 및 중지 처리 beep.timer(); //타이틀 스크린 루프는 타이틀 스크린에서 //FIRE를 누를 때까지 높은 점수를 얻습니다. while (!start) { start =titleScreen(); if (!start) { 시작 =displayHighScores(EE_FILE); } } //초기 레벨 그리기 if (!initialDraw) { //화면 지우기 arduboy.clear(); //글꼴 선택 //새 레벨을 그립니다. =1; 새로운 레벨(); 점수 =0; 초기 그리기=참; } if (live>0) { drawPaddle(); // FIRE 눌렀을 때 게임 일시 중지 패드 =arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON); if(패드 ==true &&oldpad ==false &&해제됨) { oldpad2 =false; //패드 루프 2가 한 번 실행되도록 강제합니다. pause(); } 오래된 패드 =패드; 드로볼(); if(brickCount ==행 * 열) { 레벨++; 새로운 레벨(); } } else { drawGameOver(); if (점수> 0) { enterHighScore(EE_FILE); } arduboy.clear(); initialDraw=거짓; 시작=거짓; 생명=3; 새로운 레벨(); } arduboy.display();}void movePaddle(){ //오른쪽으로 이동 if(xPaddle  0) { if (arduboy.pressed(LEFT_BUTTON)) { xPaddle-=2; } }} moveBall(){ 틱++; if(released) { //공 이동 if (abs(dx)==2) { xb +=dx/2; // 2배속은 실제로 1.5배속 if (tick%2==0) xb +=dx/2; } 그렇지 않으면 { xb +=dx; } yb=yb + dy; // 경계 설정 leftBall =xb; 오른쪽 볼 =xb + 2; 탑볼 =yb; 바텀볼 =yb + 2; // 상단 가장자리에서 바운스 if (yb <=0) { yb =2; 디 =-디; 플레이톤(523, 250); } //하단 가장자리가 히트하면 생명을 잃습니다. if (yb>=64) { arduboy.drawRect(xPaddle, 63, 11, 1, 0); x패들 =54; 연=60; 해제 =거짓; 삶--; playToneTimed(175, 500); if (무작위(0, 2) ==0) { dx =1; } 그렇지 않으면 { 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-(x패들+6))/3); //볼에 스핀을 적용합니다 // 직선 바운스를 방지 if (dx ==0) { dx =(random(0,2) ==1) ? 1:-1; } 플레이톤(200, 250); } //Bounce off Brick for (byte row =0; row =topBrick &&leftBall <=rightBrick &&rightBall>=leftBrick) { Score(); 벽돌 개수++; isHit[행][열] =true; arduboy.drawRect(10*열, 2+6*행, 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; } 그렇지 않으면 { dx =-1; } //공이 위쪽으로 향하는지 확인 dy =-1; } 오래된 패드3 =패드3; }}무효 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);}무효 drawPaddle(){ arduboy.drawRect(xPaddle, 63, 11, 1, 0); 이동 패들(); arduboy.drawRect(xPaddle, 63, 11, 1, 1);}무효 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(점수); 아두보이.디스플레이(); arduboy.delayShort(4000);}void pause(){ 일시 중지 =true; //화면에 일시정지 그리기 arduboy.setCursor(52, 45); arduboy.print("일시 중지"); 아두보이.디스플레이(); 동안 (일시 중지) { 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); 일시 중지됨=거짓; } 오래된 패드2 =패드2; }}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*열, 2+6*행, 8, 4, 1); } } arduboy.display();}//버튼을 읽는 동안 이미지를 지연시키는 데 사용 inputboolean pollFireButton(int n){ for(int i =0; i  0) { sprintf(text_buffer, "%c%c%c %u", 이니셜[0], 이니셜[1], 이니셜[2], 점수); arduboy.setCursor(x + 24, y + (i*8)); arduboy.print(텍스트 버퍼); 아두보이.디스플레이(); } } if (pollFireButton(300)) { true를 반환합니다. } 반환 거짓; arduboy.display();}boolean titleScreen(){ //화면 지우기 arduboy.clear(); arduboy.setCursor(16,22); 아두보이.setTextSize(2); arduboy.print("브레이크아웃"); 아두보이.setTextSize(1); 아두보이.디스플레이(); if (pollFireButton(25)) { true를 반환합니다. } // "Press FIRE"를 5번 플래시 for(byte i =0; i <5; i++) { //"Press FIRE"를 그립니다. arduboy.setCursor(31, 53); arduboy.print("발사를 눌러주세요!"); 아두보이.디스플레이(); if (pollFireButton(50)) { true를 반환합니다. } // "Press FIRE" 제거 arduboy.setCursor(31, 53); arduboy.print(" "); 아두보이.디스플레이(); if (pollFireButton(25)) { true를 반환합니다. } } return false;}//높은 점수를 추가하기 위한 누트로픽 디자인의 기능void enterInitials(){ byte index =0; arduboy.clear(); 이니셜[0] =' '; 이니셜[1] =' '; 이니셜[2] =' '; 동안 (참) { arduboy.display(); arduboy.clear(); arduboy.setCursor(16,0); arduboy.print("높은 점수"); sprintf(text_buffer, "%u", 점수); arduboy.setCursor(88, 0); arduboy.print(텍스트 버퍼); arduboy.setCursor(56, 20); arduboy.print(이니셜[0]); arduboy.setCursor(64, 20); arduboy.print(이니셜[1]); arduboy.setCursor(72, 20); arduboy.print(이니셜[2]); for(바이트 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 + (인덱스*8), 28, 56 + (인덱스*8) + 6, 28, 1); arduboy.delayShort(70); if (arduboy.pressed(LEFT_BUTTON) || arduboy.pressed(B_BUTTON)) { if (인덱스> 0) { 인덱스--; playToneTimed(1046, 80); } } if (arduboy.pressed(RIGHT_BUTTON)) { if (인덱스 <2) { 인덱스++; playToneTimed(1046, 80); } } if (arduboy.pressed(UP_BUTTON)) { 이니셜[인덱스]++; playToneTimed(523, 80); // AZ 0-9 :-? !-/ ' ' if (이니셜[인덱스] =='0') { 이니셜[인덱스] =' '; } if (이니셜[인덱스] =='!') { 이니셜[인덱스] ='A'; } if (이니셜[인덱스] =='[') { 이니셜[인덱스] ='0'; } if (이니셜[인덱스] =='@') { 이니셜[인덱스] ='!'; } } if (arduboy.pressed(DOWN_BUTTON)) { 이니셜[인덱스]--; playToneTimed(523, 80); if (이니셜[인덱스] ==' ') { 이니셜[인덱스] ='?'; } if (이니셜[인덱스] =='/') { 이니셜[인덱스] ='Z'; } if (이니셜[인덱스] ==31) { 이니셜[인덱스] ='/'; } if (이니셜[인덱스] =='@') { 이니셜[인덱스] =' '; } } if (arduboy.pressed(A_BUTTON)) { playToneTimed(1046, 80); if (인덱스 <2) { 인덱스++; } 그렇지 않으면 { 반환; } } }}void enterHighScore(byte file){ // EEPROM의 각 블록에는 7개의 최고 점수가 있고 각 최고 점수 항목은 // 길이가 5바이트입니다. 이니셜은 3바이트, 점수는 2바이트입니다. int 주소 =파일 * 7 * 5 + EEPROM_STORAGE_SPACE_START; 바이트 안녕하세요, 로; char 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 =(안녕 <<8) | 봐라; } if (점수> tmpScore) { enterInitials(); for(바이트 j =i; j <7; j++) { hi =EEPROM.read(주소 + (5*j)); lo =EEPROM.read(주소 + (5*j) + 1); if ((hi ==0xFF) &&(lo ==0xFF)) { tmpScore =0; } else { tmpScore =(안녕 <<8) | 봐라; } tmpInitials[0] =(char)EEPROM.read(주소 + (5*j) + 2); tmpInitials[1] =(char)EEPROM.read(주소 + (5*j) + 3); tmpInitials[2] =(char)EEPROM.read(주소 + (5*j) + 4); // 현재 슬롯에 ​​점수와 이니셜 쓰기 EEPROM.update(address + (5*j), ((score>> 8) &0xFF)); EEPROM.update(주소 + (5*j) + 1, (점수 &0xFF)); EEPROM.update(주소 + (5*j) + 2, 이니셜[0]); EEPROM.update(주소 + (5*j) + 3, 이니셜[1]); EEPROM.update(주소 + (5*j) + 4, 이니셜[2]); // tmpScore 및 tmpInitials는 이제 다음 슬롯에 // 쓰고 싶은 것을 보유합니다. 점수 =tmpScore; 이니셜[0] =tmpInitials[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. Raspi 2 WIOT와 Arduino I2C 통신
    2. 휴대용 게임 콘솔 | 아두보이 클론
    3. Arduino Pong 게임 - OLED 디스플레이
    4. Arduino Temp. 3.2 디스플레이가 있는 모니터 및 실시간 시계
    5. Arduino를 사용한 간단한 장애물 센서
    6. Nextion 디스플레이로 재생
    7. Arduino Nano:조이스틱으로 2개의 스테퍼 모터 제어
    8. Arduino 및 Nokia 5110 디스플레이가 있는 DIY 전압계
    9. Arduino 및 OLED 기반 Cellular Automata
    10. Arduino용 절연 아날로그 입력