Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Компоненты и материалы

Arduino Mega 2560×1
Adafruit 1.4" 4-разрядный 7-сегментный дисплей с I2C-рюкзаком×2
Adafruit Большая аркадная кнопка с LED (60 мм)×5
Adafruit Audio FX Board 16 МБ×1
Adafruit 2.5W усилитель×2
Динамик 3 Вт, 4 Ом×2
Adafruit Вкл/Выкл кнопка с LED×1
Adafruit Потенциометр 10 кОм×2
Adafruit Ручка потенциометра×2
Провода×1
Контрубиты M3 + гайки×1
Контрубиты M4 + гайки×1
Все 3D-печатные детали×1
Все лазерно-вырезанные MDF-детали×1
Кастомный шилд для Arduino Mega×1
Stackable headers для Arduino Mega (для зазора)×1
Adafruit DC-DC понижающий преобразователь 5В 3А×1
БП 12В×1
Разъём питания (female)×1
USB-B панельный разъём×1

Необходимые инструменты и станки

Приложения и онлайн-сервисы

О проекте

Это кастомная игра Whac-A-Mole. Пока запрограммирована базовая игра, но возможно создание обновлений в будущем.

Ключевые особенности

Корпус

Начните со сборки корпуса.

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino
DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Установите 3D-печатные крепежные кронштейны на верхнюю крышку.

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

При желании покрасьте корпус.

Далее установите крепления LED-дисплеев. Не забудьте положить болты под крепления, иначе вертикальные рейки не зафиксируются.

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Соберите Arduino-шилд. Использовал дополнительный комплект stackable headers для зазора между шилдом и Arduino.

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Соберите заднюю панель управления.

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Соберите верхнюю крышку (кнопки и LED-панели).

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino
DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino
DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino
DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Задняя панель включает два потенциометра: громкость и выбор уровня.

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino
DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Заключение

Готово!

На левом дисплее — выбранный уровень (1 — легко, 10 — безумно). На правом — рекорд для этого уровня. Во время игры левый показывает текущий счёт. Нажмите зелёную кнопку для старта. После обратного отсчёта игра начнётся.

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Код

/* 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
#define potmeterVolume 0
#define potmeterGameLevel 1
#define ampPower 32
#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
#define btn2 1
#define btn3 2
#define btn4 3
#define btn5 4
#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
#define btnLed2 1
#define btnLed3 2
#define btnLed4 3
#define btnLed5 4
#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
#define fx1Trigger 1
#define fx2Trigger 2
#define fx3Trigger 3
#define fx4Trigger 4
#define fx5Trigger 5
#define fx6Trigger 6
#define fx7Trigger 7
#define fx8Trigger 8
#define fx9Trigger 9
#define fx10Trigger 10
#define fxVolUp 0
#define fxVolDn 1
signed int currentPlayingSound = -1;
byte btnPressed[5], ledState[5];
unsigned long previousMillisLedBlink = 0;
#define intervalLedBlink 750
unsigned long previousMillisGameStarting = 0;
#define intervalCountDown 1000
byte gameStartCountDown;
unsigned long previousMillisGameStep = 0;
int gameStepLength = 0;
int gameStepBtn = 0;
int volume = 0;
int actualVolume = 35;
int valPotmeterGameLevel = 0;
int gameLevel;
int currentScore;
int highScore;
int highScoreAddr = 1;
byte activeBtn;
bool debug;
byte wackAMoleState;
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);
  pinMode(ampPower, OUTPUT);
  digitalWrite(ampPower, LOW);
  for (int Pin = 0; Pin < 5; Pin++) pinMode(btnArray[Pin], INPUT);
  for (int Pin = 0; Pin < 5; Pin++) pinMode(btnLedArray[Pin], OUTPUT);
  for (int Pin = 0; Pin < 11; Pin++) { pinMode(fxTriggerArray[Pin], OUTPUT); digitalWrite(fxTriggerArray[Pin], HIGH); }
  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());
  cli();
  highScore = eeprom_read_word((uint16_t*)(gameLevel * 2));
  sei();
  matrix1.print(0); matrix1.writeDisplay();
  matrix2.print(0); matrix2.writeDisplay();
  initializeSystem();
}

void loop() {
  checkButtonInputs();
  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);
  }
  if ((currentMillisGameStep - previousMillisGameStep >= gameStepLength) || (amountOfButtonPresses > 1) || (amountOfButtonPresses == 1 && !btnPressed[gameStepBtn])) {
    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);
    }
    for (int i = 0; i < 5; i++) analogWrite(btnLedArray[i], 0);
    Serial.println("Game Over");
    if (currentScore > highScore) {
      while (!eeprom_is_ready());
      cli();
      eeprom_write_word((uint16_t*)(gameLevel * 2), currentScore);
      sei();
    }
    int counter = 0;
    do { delay(1); checkButtonInputs(); counter++; } while ((counter < 1000) && !btnPressed[btn1] && !btnPressed[btn2] && !btnPressed[btn3] && !btnPressed[btn4] && !btnPressed[btn5]);
    matrix1.print(0); matrix1.writeDisplay();
    wackAMoleState = waitForStart;
  } else if (btnPressed[gameStepBtn] && (amountOfButtonPresses == 1)) {
    digitalWrite(btnLedArray[gameStepBtn], LOW);
    int counter = 0;
    do { delay(1); checkButtonInputs(); counter++; } while ((counter < 1000) && btnPressed[gameStepBtn]);
    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);
    currentScore++;
    matrix1.print(currentScore); matrix1.writeDisplay();
    if (currentScore > highScore) { matrix2.print(currentScore); matrix2.writeDisplay(); }
  }
}

void ledBlinkStart() {
  unsigned long currentMillisLedBlink = millis();
  if (currentMillisLedBlink - previousMillisLedBlink >= intervalLedBlink) {
    previousMillisLedBlink = currentMillisLedBlink;
    ledState[0] = (ledState[0] == LOW) ? HIGH : LOW;
    digitalWrite(btnLedArray[btnLed4], ledState[0]);
  }
}

void startGame() {
  unsigned long currentMillisGameStarting = millis();
  digitalWrite(btnLedArray[btnLed4], 0);
  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() {
  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() {
  static byte previousstate[5], currentstate[5];
  static long lasttime;
  byte index;
  if ((lasttime + debounceTime) > millis()) return;
  lasttime = millis();
  for (index = 0; index < 5; index++) {
    currentstate[index] = digitalRead(btnArray[index]);
    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());
  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); }

Кастомные детали и корпуса

Схемы

DIY аркадная игра Whac-A-Mole (кнопочная версия) — проект на Arduino

Производственный процесс

  1. Как выбрать правильные ручки приборов для вашего оборудования
  2. Выбор винтов с полукруглой головкой и шестигранником: практическое руководство
  3. Пуговица: от древней застежки к современной инновации
  4. Создание кнопки AWS IoT с управлением движением на Raspberry Pi, PIR-датчике и MQTT
  5. UnifiedWater v1: полный набор датчиков качества воды на Arduino MKR GSM
  6. Переносная система голосования с GSM-связью
  7. Как выбрать производителя прототипов печатных плат: полное руководство
  8. Выбор оптимальной скорости пиления для ленточных пил: практическое руководство
  9. Выбор правильного погружного насоса: экспертные советы и ключевые характеристики
  10. Почему стоит выбрать вертикально-токарные центры для точной обработки