SunFounder Maker Education
Published © GPL3+

How to DIY a Whack-a-Mole Game with Cardboard Box

Recently I was bothered by a lot of cartons in the house. Don't want to just throw them away as recycles so I made them into a Whack-a-Mole.

IntermediateFull instructions provided4 hours2,944
How to DIY a Whack-a-Mole Game with Cardboard Box

Things used in this project

Hardware components

Multi-Control Board
×1
Mini USB cable
×1
Dupont wires
male to female
×16
Jumper wires
male
×25
Arcade buttons
with LED
×9

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Big cardboard box
big enough for 3 x 3 buttons with gap
Soldering iron (generic)
Soldering iron (generic)
Cutting plier
Utility knife
Pencil
Ruler

Story

Read more

Schematics

Components List

We use the following components in this project, youc an check for reference.

Code

multi-control-keyboard.ino

Arduino
#include "Keyboard.h"
#include "keymap.h"

#define DEBUG 0          // When it is 1, it will print the debugging information.
#define JOYSTICK_SENSITIVITY 100 // adjust the sensitivity of joystick, ranging 0-500
#define MINTOUCH 938     // sensitivity of holes(0-1023), the larger the parameter is, the more sensitive they will be.
#define Y_AXIS 1        // define axis X/Y,used in joystickHandle
#define X_AXIS 0
#define debounceDelay 20

#define AxisUp      0
#define AxisDown    1
#define AxisLeft    2
#define AxisRight   3
#define PinUp       4
#define PinDown     5
#define PinLeft     6
#define PinRight    7
#define HoleUp      8
#define HoleDown    9
#define HoleLeft    10
#define HoleRight   11
#define PinA        12
#define PinB        13
#define PinX        14
#define PinY        15
#define PinStart    16
#define PinSelect   17
#define HoleA       18
#define HoleB       19
#define HoleX       20
#define HoleY       21
#define HoleStart   22
#define HoleSelect  23

// threshold of the joystick to shift to digital value, if larger than MAX, UP input; if smaller than MAX, DOWN input.
int MAXJOYSTICK = 1023 - JOYSTICK_SENSITIVITY;
int MINJOYSTICK = 0 + JOYSTICK_SENSITIVITY;

//==============================================
// set pin numbers for the buttons:
const int joystickXAxis    = A0;
const int joystickYAxis    = A11;
const int pinUp            = 16;
const int pinLeft          = 15;
const int pinDown          = 14;
const int pinRight         = 13;
const int pinA             = 3;
const int pinB             = 2;
const int pinX             = 11;
const int pinY             = 5;
const int pinStart         = 0;
const int pinSelect        = 1;
const int Mode             = 7;

// analog clip hole:
const int holeUp           = A1;
const int holeLeft         = A2;
const int holeDown         = A3;
const int holeRight        = A4;
const int holeSelect       = A5;
const int holeStart        = A6;
const int holeA            = A7;
const int holeB            = A8;
const int holeX            = A9;
const int holeY            = A10;
//==============================================

int statusMode = 0;// if mode on left(==0),hole key enable


//==============================================
// Creat a struct type named status_struct
struct status_struct{
  int pin;     // pin number
  int cStatus; // current_status
  int lStatus; // last_status
  int key;     // key value
  bool isXY;    // is x or y axis
  unsigned long dTime;  // lastDebounceTime
  bool sent;    // sent flag
};
//==============================================
// Creat an array, the member type is status_struct
status_struct  state[] = {
// pin      cStatus  lStatus   key       isXY dTime sent
  {joystickYAxis, 0, 0, KEYBOARD_UP,     Y_AXIS, 0, 0},
  {joystickXAxis, 0, 0, KEYBOARD_LEFT,   X_AXIS, 0, 0},
  {joystickYAxis, 0, 0, KEYBOARD_DOWN,   Y_AXIS, 0, 0},
  {joystickXAxis, 0, 0, KEYBOARD_RIGHT,  X_AXIS, 0, 0},
  {pinUp,         0, 0, KEYBOARD_UP,     Y_AXIS, 0, 0},
  {pinDown,       0, 0, KEYBOARD_DOWN,   Y_AXIS, 0, 0},
  {pinLeft,       0, 0, KEYBOARD_LEFT,   X_AXIS, 0, 0},
  {pinRight,      0, 0, KEYBOARD_RIGHT,  X_AXIS, 0, 0},
  {holeUp,        0, 0, KEYBOARD_UP,     Y_AXIS, 0, 0},
  {holeDown,      0, 0, KEYBOARD_DOWN,   Y_AXIS, 0, 0},
  {holeLeft,      0, 0, KEYBOARD_LEFT,   X_AXIS, 0, 0},
  {holeRight,     0, 0, KEYBOARD_RIGHT,  X_AXIS, 0, 0},
  {pinA,          0, 0, KEYBOARD_A,      NULL,   0, 0},
  {pinB,          0, 0, KEYBOARD_B,      NULL,   0, 0},
  {pinX,          0, 0, KEYBOARD_X,      NULL,   0, 0},
  {pinY,          0, 0, KEYBOARD_Y,      NULL,   0, 0},
  {pinStart,      0, 0, KEYBOARD_START,  NULL,   0, 0},
  {pinSelect,     0, 0, KEYBOARD_SELECT, NULL,   0, 0},
  {holeA,         0, 0, KEYBOARD_A,      NULL,   0, 0},
  {holeB,         0, 0, KEYBOARD_B,      NULL,   0, 0},
  {holeX,         0, 0, KEYBOARD_X,      NULL,   0, 0},
  {holeY,         0, 0, KEYBOARD_Y,      NULL,   0, 0},
  {holeStart,     0, 0, KEYBOARD_START,  NULL,   0, 0},
  {holeSelect,    0, 0, KEYBOARD_SELECT, NULL,   0, 0}};
//==============================================

// initialize the buttons' inputs:
void setup() {
  pinMode(pinUp,        INPUT_PULLUP);
  pinMode(pinLeft,      INPUT_PULLUP);
  pinMode(pinDown,      INPUT_PULLUP);
  pinMode(pinRight,     INPUT_PULLUP);
  pinMode(pinA,         INPUT_PULLUP);
  pinMode(pinB,         INPUT_PULLUP);
  pinMode(pinX,         INPUT_PULLUP);
  pinMode(pinY,         INPUT_PULLUP);
  pinMode(pinStart,     INPUT_PULLUP);
  pinMode(pinSelect,    INPUT_PULLUP);
  pinMode(Mode,         INPUT_PULLUP);

  Serial.begin(9600);
  Keyboard.begin();
}

void debounced_read(int num){ // digitalRead and dithering elimination
  int reading = digitalRead(state[num].pin);

  if (reading != state[num].lStatus) {
    state[num].dTime = millis();
  }

  if ((millis() - state[num].dTime) > debounceDelay) {
    if (reading != state[num].cStatus) {
      state[num].cStatus = reading;
      Serial.println("have a input");
      state[num].sent = 1;
    }
  }
  state[num].lStatus = reading;
}

void analog_read(int num){ // analogRead, and shift to digital one to store
  bool threshold;
  int value      = analogRead(state[num].pin);
  if(num < 4){  // if is joystick pin
    if(num==0 || num==3)       // if is up or right
      threshold = (value > MAXJOYSTICK);
    else if (num==1 || num==2) // if is down or left
      threshold = (value < MINJOYSTICK);
  }
  else          // if is hole pin
    threshold = (value < MINTOUCH);

  if (threshold)     // the status is pressed
    state[num].cStatus    = 0;
  else               // the status is released
    state[num].cStatus    = 1;

  if (state[num].lStatus != state[num].cStatus) { // handle it when its state changes
    state[num].sent = 1;
    state[num].lStatus = state[num].cStatus;
  }
}

void readStatus() {  // read status
  debounced_read(PinUp);
  debounced_read(PinDown);
  debounced_read(PinLeft);
  debounced_read(PinRight);
  debounced_read(PinA);
  debounced_read(PinB);
  debounced_read(PinX);
  debounced_read(PinY);
  debounced_read(PinStart);
  debounced_read(PinSelect);

  analog_read(AxisUp);
  analog_read(AxisDown);
  analog_read(AxisLeft);
  analog_read(AxisRight);

  statusMode = digitalRead(Mode);
  if (statusMode == 0){  // Enable Hole Mode
    analog_read(HoleUp);
    analog_read(HoleLeft);
    analog_read(HoleDown);
    analog_read(HoleRight);
    analog_read(HoleA);
    analog_read(HoleB);
    analog_read(HoleX);
    analog_read(HoleY);
    analog_read(HoleStart);
    analog_read(HoleSelect);
  }
}

// Serial Plotter
void debug(int value){
  Serial.print(value);Serial.print(',');
}
void printValue(bool holes, bool axis, bool pins){
  if (holes){ // printValue holes status
    debug(state[HoleUp].cStatus);
    debug(state[HoleLeft].cStatus);
    debug(state[HoleDown].cStatus);
    debug(state[HoleRight].cStatus);
    debug(state[HoleSelect].cStatus);
    debug(state[HoleStart].cStatus);
    debug(state[HoleA].cStatus);
    debug(state[HoleB].cStatus);
    debug(state[HoleX].cStatus);
    debug(state[HoleY].cStatus);
    debug(MINTOUCH);
  }
  if (axis){ // printValue axis status
    debug(state[AxisUp].cStatus);
    debug(state[AxisDown].cStatus);
    debug(state[AxisLeft].cStatus);
    debug(state[AxisRight].cStatus);
    debug(state[AxisUp].lStatus);
    debug(state[AxisDown].lStatus);
    debug(state[AxisLeft].lStatus);
    debug(state[AxisRight].lStatus);
  }
  if (pins){ // printValue pins status
    debug(state[PinUp].cStatus);
    debug(state[PinDown].cStatus);
    debug(state[PinLeft].cStatus);
    debug(state[PinRight].cStatus);
    debug(state[PinA].cStatus);
    debug(state[PinB].cStatus);
    debug(state[PinX].cStatus);
    debug(state[PinY].cStatus);
    debug(state[PinStart].cStatus);
    debug(state[PinSelect].cStatus);
  }
  Serial.println(' ');
}

// Handle press command
void pressHandle(int key) {
  Keyboard.press(key);
}

// Handle release command
void releaseHandle(int key) {
  Keyboard.release(key);
}

// Handle for Buttons functions
void keyHandle(int num){
  if (state[num].sent) {
    if (state[num].cStatus == 0){
      debug(state[num].cStatus);debug(state[num].lStatus);
      //Serial.print(num);Serial.println(" pressed");
      pressHandle(state[num].key);
    }
    else
      releaseHandle(state[num].key);
    state[num].sent = 0;
  }
  delay(1);
}

// Scan all the buttons status
void scan() {
  // Buttons
  keyHandle(PinUp);
  keyHandle(AxisUp);
  keyHandle(PinDown);
  keyHandle(AxisDown);
  keyHandle(PinLeft);
  keyHandle(AxisLeft);
  keyHandle(PinRight);
  keyHandle(AxisRight);
  keyHandle(PinA);
  keyHandle(PinB);
  keyHandle(PinX);
  keyHandle(PinY);
  keyHandle(PinStart);
  keyHandle(PinSelect);

  if (statusMode == 0){  // Enable Hole Mode
    keyHandle(HoleUp);
    keyHandle(HoleDown);
    keyHandle(HoleLeft);
    keyHandle(HoleRight);
    keyHandle(HoleA);
    keyHandle(HoleB);
    keyHandle(HoleX);
    keyHandle(HoleY);
    keyHandle(HoleStart);
    keyHandle(HoleSelect);
  }
}

void loop() {
  readStatus();
  //printValue(1,1,1); // holes, axis, pins
  scan();
}

keymap.h

Arduino
#include "Keyboard.h"

#define KEY_SPACE       0x20

// you can check the button modifer in list if you want to customize the value at the right of equal sign
// KEYBOARD_MODE
int KEYBOARD_UP     = KEY_UP_ARROW;
int KEYBOARD_DOWN   = KEY_DOWN_ARROW;
int KEYBOARD_LEFT   = KEY_LEFT_ARROW;
int KEYBOARD_RIGHT  = KEY_RIGHT_ARROW;
int KEYBOARD_A      = KEY_LEFT_CTRL;
int KEYBOARD_B      = KEY_LEFT_ALT;
int KEYBOARD_X      = 'z';
int KEYBOARD_Y      = 'x';
int KEYBOARD_SELECT = KEY_SPACE;
int KEYBOARD_START  = KEY_RETURN;

// Keyboard value defination: https://www.arduino.cc/en/Reference/KeyboardModifiers
//
// The Leonardo's definitions for modifier keys are listed below:
//
//     Key               Hexadecimal value    Decimal value
//     KEY_LEFT_CTRL           0x80                128
//     KEY_LEFT_SHIFT          0x81                129
//     KEY_LEFT_ALT            0x82                130
//     KEY_LEFT_GUI            0x83                131
//     KEY_RIGHT_CTRL          0x84                132
//     KEY_RIGHT_SHIFT         0x85                133
//     KEY_RIGHT_ALT           0x86                134
//     KEY_RIGHT_GUI           0x87                135
//     KEY_UP_ARROW            0xDA                218
//     KEY_DOWN_ARROW          0xD9                217
//     KEY_LEFT_ARROW          0xD8                216
//     KEY_RIGHT_ARROW         0xD7                215
//     KEY_BACKSPACE           0xB2                178
//     KEY_TAB                 0xB3                179
//     KEY_RETURN              0xB0                176
//     KEY_ESC                 0xB1                177
//     KEY_INSERT              0xD1                209
//     KEY_DELETE              0xD4                212
//     KEY_PAGE_UP             0xD3                211
//     KEY_PAGE_DOWN           0xD6                214
//     KEY_HOME                0xD2                210
//     KEY_END                 0xD5                213
//     KEY_CAPS_LOCK           0xC1                193
//     KEY_F1                  0xC2                194
//     KEY_F2                  0xC3                195
//     KEY_F3                  0xC4                196
//     KEY_F4                  0xC5                197
//     KEY_F5                  0xC6                198
//     KEY_F6                  0xC7                199
//     KEY_F7                  0xC8                200
//     KEY_F8                  0xC9                201
//     KEY_F9                  0xCA                202
//     KEY_F10                 0xCB                203
//     KEY_F11                 0xCC                204
//     KEY_F12                 0xCD                205
//     KEY_SPACE               0x20                32

Credits

SunFounder Maker Education

SunFounder Maker Education

0 projects • 3 followers
Hacking, having fun!

Comments