DIY: Whac-A-Mole Game With Arduino

1,482

21

2

Published

Introduction: DIY: Whac-A-Mole Game With Arduino

About: I make a part time wood craftsmen and love to build things. I would be posting instructable mainly about the home decor things.

When boredom strikes, one feels like doing something interesting. Playing games becomes a fun way to beat the blues and stay entertained.

This is a custom whac-a-mole game. For now it's programmed with a basic game, but it's possible to create updates in the feature.

You and your friends can challenge each other for beating high scores!!!!!!!.

Keep playing . Let's Start.

Step 1: So,what's Different in This Game Console?

5 bottons for the game itself. Each button has it's own bright led. Led's are PWM controlled (used for the game-over sequence).

10 selectable levels.

Level 1 (easy) through 10 (insane).

During gameplay you have to hit the correct button within a certain time.

This duration is variable inside each level (so sometimes you have to press is quicker than other steps).

Random button selection during gameplay.

The next step (button that needs to be pressed) is always an other button.

2 LED digit displays.

One for current score/countdown/level selection and one for displaying high score.

Digital volume control

High score storing

Sound effects.

During various states of the game sound loops are played through the build-in speakers.

Laser cut enclosure

Many 3D printed parts

Custom Arduino Mega shield

Step 2: Things/Parts Required

Arduino Mega 2560 & Genuino Mega 2560 x1

Adafruit 1.4" 4-digit 7-segment display with I2C backpack x2

Adafruit Big arcade button with led (60mm) x5

Adafruit Big arcade button with led (60mm) x1

Adafruit Audio fx board 16mb x1

Adafruit 2.5w amp x2

Speaker: 3W, 4 ohms x2

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

Step 3: Make a Enclosure-Bottom & Top

Start by making the bottom.

The design are included in the CAD files.

You can make any design as per your needs.

Step 4: Next Mounting Parts

Mount the 3D printed mounting brackets on the top cover.

If you wish, paint the enclosure.

Step 5: Continue...

Next, mount the LED display mounts. Don't forget to place the bolts underneath the mounts, otherwise the vertical bars can't be fixed.

Step 6: Schematics

Step 7: Assembly

Assemble the Arduino shield. I used an extra set of stackable headers, so there's more space between the shield and the Arduino.

Step 8: Next, Assemble the Back Control Panel.

Step 9: Assemble the Top Cover (buttons & LED Panels)

Step 10: Arduino Code

#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); }

Step 11: Total Wiring

Step 12: PCB Wiring Detail

Step 13: Back Control Panel

The back control panel includes two potentiometer controls; one for the volume control, one for level selection.

Step 14: Finished!

On the left led digit panel you can see the selected level.

You can select level 1 (easy) through 10 (insane).

the right led digit panel you can see the high score for the corresponding level.

During an active game the left digit panel will display the current score.

Now press the green button to start the game.

After a countdown the game will start.

If you like this please like, and vote. Follow me for more updates.

Game Life Contest

This is an entry in the
Game Life Contest

Share

    Recommendations

    • Creative Misuse Contest

      Creative Misuse Contest
    • Water Contest

      Water Contest
    • Clocks Contest

      Clocks Contest

    2 Discussions

    looks cool!

    0
    user
    bhm133

    14 days ago

    Awesome. Looks like an exciting build and a lot of fun. Good instructable!