Game Arcade Whac-A-Mole DIY (Edisi Tombol) – Proyek Arduino
Komponen dan Perlengkapan
| Arduino Mega 2560 | 1 |
| Adafruit 1.4" 4-digit 7-segment display with I2C backpack | 2 |
| Adafruit Big arcade button with led (60mm) | 5 |
| Adafruit Audio fx board 16mb | 1 |
| Adafruit 2.5w amp | 2 |
| Speaker: 3W, 4 ohms | 2 |
| Adafruit on/off button with led | 1 |
| Adafruit potentiometer 10 k | 2 |
| Adafruit potentiometer knob | 2 |
| wire | 1 |
| Countersunk screws M3 + nuts | 1 |
| Countersunk screws M4 + nuts | 1 |
| All 3d printed parts | 1 |
| All lasercut MDF parts | 1 |
| Custom Arduino mega shield | 1 |
| Arduino mega stackable headers (for spacing) | 1 |
| Adafruit DC step-down converter 5v 3A | 1 |
| 12v PSU | 1 |
| Female psu bus | 1 |
| USB-B panelmount | 1 |
Alat dan Mesin yang Diperlukan
| 3D Printer (generic) |
| screwdriver |
| Soldering iron (generic) |
Aplikasi dan Layanan Online
| Arduino IDE |
| MDF lasercut service |
Tentang Proyek Ini
Ini adalah game Whac-A-Mole kustom. Untuk saat ini, diprogram dengan game dasar, tetapi memungkinkan untuk membuat pembaruan di masa depan.
Key features:
- 5 tombol untuk game itu sendiri. Setiap tombol memiliki LED terangnya sendiri. LED dikontrol PWM (digunakan untuk urutan game-over).
- 10 level yang dapat dipilih. Level 1 (mudah) hingga 10 (gila). Selama gameplay, Anda harus menekan tombol yang benar dalam waktu tertentu. Durasi ini bervariasi di setiap level (jadi terkadang Anda harus menekannya lebih cepat dari langkah lainnya).
- Pemilihan tombol (pseudo) acak selama gameplay. Langkah berikutnya (tombol yang perlu ditekan) selalu tombol lain.
- 2 tampilan digit LED. Satu untuk skor saat ini/hitung mundur/pemilihan level dan satu untuk menampilkan skor tertinggi.
- Kontrol volume digital
- Penyimpanan skor tertinggi
- Efek suara. Selama berbagai status game, loop suara diputar melalui speaker bawaan.
- Cakaran dipotong laser
- Banyak bagian cetakan 3D
- Shield Arduino Mega kustom
Enclosure
Pertama, mulai dengan merangkaian cakaran.
Pasang bracket mounting cetakan 3D pada tutup atas.
Jika ingin, cat cakaran.
Selanjutnya, pasang mount tampilan LED. Jangan lupa untuk menempatkan baut di bawah mount, sebaliknya batang vertikal tidak dapat dikunci.
Rangkaian shield Arduino. Saya menggunakan set tambahan stackable headers, sehingga ada lebih banyak ruang antara shield dan Arduino.
Rangkaian panel kontrol belakang.
Rangkaian tutup atas (tombol & panel LED).
Panel kontrol belakang mencakup dua kontrol potensio; satu untuk kontrol volume, satu untuk pemilihan level.
Conclusions
Selesai!
di panel digit LED kiri Anda dapat melihat level yang dipilih. Anda dapat memilih level 1 (mudah) melalui 10 (gila). Di panel digit LED kanan Anda dapat melihat skor tertinggi untuk level yang sesuai. Selama game aktif, panel digit kiri akan menampilkan skor saat ini. Sekarang tekan tombol hijau untuk memulai game. Setelah hitung mundur game akan dimulai.
Kode
Whac_A_Mole_v1.0.0Arduino
Arduino Code, written within Visual Studio
/* Whac_A_Mole_v1.0.0 By WT040 */ #include "Wire.h" #include "Adafruit_LEDBackpack.h" #include "Adafruit_GFX.h" Adafruit_7segment matrix1 = Adafruit_7segment(); Adafruit_7segment matrix2 = Adafruit_7segment(); #define debounceTime 10 //declare potmeter controls #define potmeterVolume 0 #define potmeterGameLevel 1 //declare amp power pin #define ampPower 32 //declare buttons #define btn1Pin 22 #define btn2Pin 24 #define btn3Pin 26 #define btn4Pin 28 #define btn5Pin 30 byte btnArray[] = { btn1Pin, btn2Pin, btn3Pin, btn4Pin, btn5Pin }; #define btn1 0 // for using the btn array #define btn2 1 // for using the btn array #define btn3 2 // for using the btn array #define btn4 3 // for using the btn array #define btn5 4 // for using the btn array //declare button leds #define btnLed1Pin 9 #define btnLed2Pin 10 #define btnLed3Pin 11 #define btnLed4Pin 12 #define btnLed5Pin 13 byte btnLedArray[] = { btnLed1Pin, btnLed2Pin, btnLed3Pin, btnLed4Pin, btnLed5Pin }; #define btnLed1 0 // for using the btn array #define btnLed2 1 // for using the btn array #define btnLed3 2 // for using the btn array #define btnLed4 3 // for using the btn array #define btnLed5 4 // for using the btn array //declare audio fx digitals #define fx0TriggerPin 29 #define fx1TriggerPin 31 #define fx2TriggerPin 33 #define fx3TriggerPin 35 #define fx4TriggerPin 37 #define fx5TriggerPin 39 #define fx6TriggerPin 41 #define fx7TriggerPin 43 #define fx8TriggerPin 45 #define fx9TriggerPin 47 #define fx10TriggerPin 49 #define fxVolUpPin 51 #define fxVolDnPin 53 byte fxTriggerArray[] = { fx0TriggerPin, fx1TriggerPin, fx2TriggerPin, fx3TriggerPin, fx4TriggerPin, fx5TriggerPin, fx6TriggerPin, fx7TriggerPin, fx8TriggerPin, fx9TriggerPin, fx10TriggerPin }; byte fxVolumeArray[] = { fxVolUpPin, fxVolDnPin }; #define fx0Trigger 0 // for using the btn array #define fx1Trigger 1 // for using the btn array #define fx2Trigger 2 // for using the btn array #define fx3Trigger 3 // for using the btn array #define fx4Trigger 4 // for using the btn array #define fx5Trigger 5 // for using the btn array #define fx6Trigger 6 // for using the btn array #define fx7Trigger 7 // for using the btn array #define fx8Trigger 8 // for using the btn array #define fx9Trigger 9 // for using the btn array #define fx10Trigger 10 // for using the btn array #define fxVolUp 0 // for using the btn array #define fxVolDn 1 // for using the btn array signed int currentPlayingSound = -1; byte btnPressed[5], ledState[5]; //blink led unsigned long previousMillisLedBlink = 0; //for blinking led #define intervalLedBlink 750 // //game start sequence unsigned long previousMillisGameStarting = 0; #define intervalCountDown 1000 byte gameStartCountDown; // //game steps unsigned long previousMillisGameStep = 0; int gameStepLength = 0; //length of an individual step int gameStepBtn = 0; //the button that's need to be pushed // int valPotmeterVolume = 0; int volume = 0; int actualVolume = 35; //volume of the adafruit fx board int valPotmeterGameLevel = 0; int gameLevel; int currentScore; int highScore; int highScoreAddr = 1; byte activeBtn; bool debug; //enable debug or not byte wackAMoleState; //state of the game bool SystemInitialized = false; #define stateUnknown 0 #define waitForStart 1 #define starting 2 #define running 3 #define gameOver 4 #define stopped 5 void setup() { Serial.begin(9600); //init amp power pin pinMode(ampPower, OUTPUT); digitalWrite(ampPower, LOW); //init btn pins for (int Pin = 0; Pin < 5; Pin++) { pinMode(btnArray[Pin], INPUT); } //init btn led pins for (int Pin = 0; Pin < 5; Pin++) { pinMode(btnLedArray[Pin], OUTPUT); } //init btn fx pins for (int Pin = 0; Pin < 11; Pin++) { pinMode(fxTriggerArray[Pin], OUTPUT); digitalWrite(fxTriggerArray[Pin], HIGH); } //init btn fx volume pins for (int Pin = 0; Pin < 2; Pin++) { pinMode(fxVolumeArray[Pin], OUTPUT); digitalWrite(fxVolumeArray[Pin], HIGH); } matrix1.begin(0x70); matrix2.begin(0x71); while (!eeprom_is_ready()); // Wait for EEPROM to be ready cli(); highScore = eeprom_read_word((uint16_t*)(gameLevel * 2)); sei(); matrix1.print(0); matrix1.writeDisplay(); matrix2.print(0); matrix2.writeDisplay(); initializeSystem(); } void loop() { checkButtonInputs(); // when we check the switches we'll get the current state readVolumePotmeter(); if (wackAMoleState == waitForStart) { playSound(fx0Trigger); if (btnPressed[btn4]) { wackAMoleState = starting; } readGameLevelPotmeter(); ledBlinkStart(); } if (wackAMoleState == starting) { startGame(); } if (wackAMoleState == running) { playSound(fx1Trigger); checkNextGameStep(); } } void checkNextGameStep() { unsigned long currentMillisGameStep = millis(); int amountOfButtonPresses = 0; for (int btn = 0; btn < 5; btn++) { if (btnPressed[btn]) { amountOfButtonPresses++; } } if (previousMillisGameStep == 0) { previousMillisGameStep = currentMillisGameStep; digitalWrite(btnLedArray[btnLed4], LOW); randomSeed(analogRead(2)); gameStepBtn = random(0, 5); gameStepLength = random(3000 / gameLevel, 5000 / gameLevel); digitalWrite(btnLedArray[gameStepBtn], HIGH); //light up new button light } if ((currentMillisGameStep - previousMillisGameStep >= gameStepLength) || (amountOfButtonPresses > 1) || (amountOfButtonPresses == 1) && !btnPressed[gameStepBtn]) { //Game over... playSound(fx2Trigger); wackAMoleState = gameOver; previousMillisGameStep = 0; for (int counter = 0; counter < 5; counter++) { analogWrite(btnLedArray[counter], 255); } for (int brightness = 255; brightness > 0; brightness--) { analogWrite(btnLedArray[btnLed1], brightness); analogWrite(btnLedArray[btnLed2], brightness); analogWrite(btnLedArray[btnLed3], brightness); analogWrite(btnLedArray[btnLed4], brightness); analogWrite(btnLedArray[btnLed5], brightness); delay(10); } analogWrite(btnLedArray[btnLed1], 0); analogWrite(btnLedArray[btnLed2], 0); analogWrite(btnLedArray[btnLed3], 0); analogWrite(btnLedArray[btnLed4], 0); analogWrite(btnLedArray[btnLed5], 0); Serial.println("Game OVer"); if (currentScore > highScore) { while (!eeprom_is_ready()); // Wait for EEPROM to be ready cli(); eeprom_write_word((uint16_t*)(gameLevel * 2), currentScore); // Let's initialize our value into EEPROM sei(); } int counter = 0; do { delay(1); checkButtonInputs(); counter++; } while ((counter < 1000) && !btnPressed[btn1] && !btnPressed[btn2 && !btnPressed[btn3] && !btnPressed[btn4] && !btnPressed[btn5]]);//wait for the release of the button matrix1.print(0); matrix1.writeDisplay(); wackAMoleState = waitForStart; } else if (btnPressed[gameStepBtn] && (amountOfButtonPresses == 1)) { digitalWrite(btnLedArray[gameStepBtn], LOW); //turn off led previous button int counter = 0; do { delay(1); checkButtonInputs(); counter++; } while ((counter < 1000) && btnPressed[gameStepBtn]);//wait for the release of the button previousMillisGameStep = currentMillisGameStep; int tempStepBtn = 0; do { tempStepBtn = random(0, 5); gameStepLength = random(3000 / gameLevel, 5000 / gameLevel); } while (gameStepBtn == tempStepBtn); gameStepBtn = tempStepBtn; digitalWrite(btnLedArray[gameStepBtn], HIGH); //light up new button light currentScore++; matrix1.print(currentScore); matrix1.writeDisplay(); if (currentScore > highScore) { matrix2.print(currentScore); matrix2.writeDisplay(); } } } void ledBlinkStart() //blink a led without delay { unsigned long currentMillisLedBlink = millis(); if (currentMillisLedBlink - previousMillisLedBlink >= intervalLedBlink) { previousMillisLedBlink = currentMillisLedBlink; if (ledState[0] == LOW) { ledState[0] = HIGH; } else { ledState[0] = LOW; } digitalWrite(btnLedArray[btnLed4], ledState[0]); //green led/button } } void startGame() //start sequence of the game itself { unsigned long currentMillisGameStarting = millis(); digitalWrite(btnLedArray[btnLed4], 0); //turn green led/button off currentScore = 0; if (gameStartCountDown == 0) { playSound(fx3Trigger); previousMillisGameStarting = millis(); gameStartCountDown = 4; delay(300); matrix1.print(gameStartCountDown, DEC); matrix1.writeDisplay(); } if (currentMillisGameStarting - previousMillisGameStarting >= intervalCountDown) { previousMillisGameStarting = currentMillisGameStarting; if (gameStartCountDown > 0) { gameStartCountDown--; matrix1.print(gameStartCountDown, DEC); matrix1.writeDisplay(); if (gameStartCountDown == 0) { wackAMoleState = running; } } } } void initializeSystem() { //add init code here... digitalWrite(btnLedArray[btnLed1], HIGH); delay(75); digitalWrite(btnLedArray[btnLed2], HIGH); delay(75); digitalWrite(btnLedArray[btnLed3], HIGH); delay(75); digitalWrite(btnLedArray[btnLed4], HIGH); delay(75); digitalWrite(btnLedArray[btnLed5], HIGH); delay(1000); digitalWrite(btnLedArray[btnLed5], LOW); delay(75); digitalWrite(btnLedArray[btnLed4], LOW); delay(75); digitalWrite(btnLedArray[btnLed3], LOW); delay(75); digitalWrite(btnLedArray[btnLed2], LOW); delay(75); digitalWrite(btnLedArray[btnLed1], LOW); delay(1000); debug = true; wackAMoleState = waitForStart; initVolume(); if (actualVolume > 0) { enableAmpPower(true); } } void checkButtonInputs() //check for button changes { static byte previousstate[5]; static byte currentstate[5]; static long lasttime; byte index; //debounce if ((lasttime + debounceTime) > millis()) { return; } lasttime = millis(); // for (index = 0; index < 5; index++) { currentstate[index] = digitalRead(btnArray[index]); // read the button if (currentstate[index] != btnPressed[index]) { if ((btnPressed[index] == HIGH) && (currentstate[index] == LOW)) { if (debug) { Serial.print("button released: "); Serial.println(index + 1); } btnPressed[index] = 0; } if ((btnPressed[index] == LOW) && (currentstate[index] == HIGH)) { if (debug) { Serial.print("button pressed: "); Serial.println(index + 1); } btnPressed[index] = 1; } } } } void initVolume() { valPotmeterVolume = (analogRead(potmeterVolume) / 30); if (actualVolume > valPotmeterVolume) { do { digitalWrite(fxVolumeArray[fxVolDn], LOW); actualVolume--; delay(20); digitalWrite(fxVolumeArray[fxVolDn], HIGH); delay(20); } while (actualVolume > valPotmeterVolume); } else if (actualVolume < valPotmeterVolume) { do { digitalWrite(fxVolumeArray[fxVolUp], LOW); actualVolume++; delay(20); digitalWrite(fxVolumeArray[fxVolUp], HIGH); delay(20); } while (actualVolume < valPotmeterVolume); } } void readVolumePotmeter() { valPotmeterVolume = (analogRead(potmeterVolume) / 30); if (actualVolume > valPotmeterVolume) { digitalWrite(fxVolumeArray[fxVolDn], LOW); actualVolume--; delay(40); digitalWrite(fxVolumeArray[fxVolDn], HIGH); if (actualVolume == 0) { enableAmpPower(false); } } else if (actualVolume < valPotmeterVolume) { digitalWrite(fxVolumeArray[fxVolUp], LOW); if (actualVolume == 0) { enableAmpPower(true); } actualVolume++; delay(40); digitalWrite(fxVolumeArray[fxVolUp], HIGH); } } void readGameLevelPotmeter() { valPotmeterGameLevel = analogRead(potmeterGameLevel); if (valPotmeterGameLevel < 102) { gameLevel = 1; } else if (valPotmeterGameLevel < 204) { gameLevel = 2; } else if (valPotmeterGameLevel < 306) { gameLevel = 3; } else if (valPotmeterGameLevel < 408) { gameLevel = 4; } else if (valPotmeterGameLevel < 510) { gameLevel = 5; } else if (valPotmeterGameLevel < 612) { gameLevel = 6; } else if (valPotmeterGameLevel < 714) { gameLevel = 7; } else if (valPotmeterGameLevel < 816) { gameLevel = 8; } else if (valPotmeterGameLevel < 918) { gameLevel = 9; } else { gameLevel = 10; } matrix1.print(gameLevel); matrix1.writeDisplay(); while (!eeprom_is_ready()); // Wait for EEPROM to be ready cli(); highScore = eeprom_read_word((uint16_t*)(gameLevel * 2)); sei(); if (highScore > -1) { matrix2.print(highScore); } else { matrix2.print(0); } matrix2.writeDisplay(); } void playSound(int sound) { if (currentPlayingSound != sound) { for (int counter = 0; counter < 11; counter++) { digitalWrite(fxTriggerArray[counter], HIGH); } digitalWrite(fxTriggerArray[sound], LOW); currentPlayingSound = sound; } } void enableAmpPower(bool state) { digitalWrite(ampPower, state); }
Bagian dan Enclosure Kustom
Lasercut MDF parts 6mm
OC9CvHjuTzsYL9POZCJt.dxfLasercut MDF parts 9mm
1irkeqvO4ABzhKqhmyG7.dxfLasercut Plexiglass parts 3mm
j4Tnmni6dQ0KXJtiHcy1.dxfCustom Arduino Mega Shield
5yiRX1RdQuPX0gNXjYkm.zip3D printed amp mount, print 2x3D printed arduino mega mount3D printed back connection panel mount3D printed back connection panel3D printed Cable Clip, print as many as you like3D printed led display mount, print 2x3D printed led display mount lock, print 4x3D printed led display top frame, print 2x3D printed top cover mount back3D printed top cover mount front, print 2x3D printed top cover mount side, print 2x
Skema