Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

DIY Whac-A-Mole Arcade-Spiel (Tasten-Edition) – Arduino Mega Projekt

Komponenten & Materialien

Arduino Mega 2560 ×1
Adafruit 1.4″ 4-stelliges 7-Segment-Display (I2C) ×2
Adafruit Arcade-Taster 60mm mit LED (5 Farben) ×5
Adafruit Audio FX Board 16MB ×1
Adafruit 2.5W Verstärker ×2
Lautsprecher 3W/4Ω ×2
Adafruit Ein/Aus-Taster mit LED, 2× 10k Potis + Knöpfe je ×1/2
Custom Arduino Mega Shield, Stapel-Headers, DC-DC 5V/3A, 12V Netzteil je ×1
Lasergeschnittenes MDF (6mm, 9mm), Plexiglas 3mm, 3D-Druckteile 1 Satz
Schrauben M3/M4, USB-B Panelmount, Kabel diverse

Werkzeuge

Apps & Services

Über das Projekt

Ein individuelles Whac-A-Mole-Spiel. Aktuell mit Basisspiel programmiert, erweiterbar für Updates.

Hauptfeatures

Gehäuse montieren

  1. 3D-gedruckte Halterungen auf Deckel schrauben.
  2. Optional lackieren.
  3. Display-Halterungen montieren (Muttern unter Halterung, sonst blockieren Vertikalstreben).
  4. Custom Shield aufbauen (Stapel-Headers für Abstand).
  5. Rückwand-Bedienfeld zusammenbauen (Volume & Level-Potis).
  6. Deckel bestücken: 5 Tasten + 2 Display-Panels.

DIY Whac-A-Mole Arcade-Spiel (Tasten-Edition) – Arduino Mega Projekt

Fazit

Fertig! Linkes Display: Levelwahl (1–10), rechtes: Highscore für dieses Level. Grün-Taste startet Countdown → Spielbeginn.

DIY Whac-A-Mole Arcade-Spiel (Tasten-Edition) – Arduino Mega Projekt

Code (Whac_A_Mole_v1.0.0)

/* 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 btnLed1Pin 9
#define btnLed2Pin 10
#define btnLed3Pin 11
#define btnLed4Pin 12
#define btnLed5Pin 13
byte btnLedArray[] = { btnLed1Pin, btnLed2Pin, btnLed3Pin, btnLed4Pin, btnLed5Pin };

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

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 actualVolume = 35;
int gameLevel;
int currentScore;
int highScore;
int highScoreAddr = 1;

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 i=0;i<5;i++) pinMode(btnArray[i], INPUT);
  for (int i=0;i<5;i++) pinMode(btnLedArray[i], OUTPUT);
  for (int i=0;i<11;i++) { pinMode(fxTriggerArray[i], OUTPUT); digitalWrite(fxTriggerArray[i], HIGH); }
  for (int i=0;i<2;i++) { pinMode(fxVolumeArray[i], OUTPUT); digitalWrite(fxVolumeArray[i], 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[3]) wackAMoleState = starting; // btn4 = Index 3
    readGameLevelPotmeter();
    ledBlinkStart();
  }
  if (wackAMoleState == starting) startGame();
  if (wackAMoleState == running) {
    playSound(fx1Trigger);
    checkNextGameStep();
  }
}

void checkNextGameStep() {
  unsigned long now = millis();
  int presses = 0;
  for (int i=0;i<5;i++) if (btnPressed[i]) presses++;

  if (previousMillisGameStep == 0) {
    previousMillisGameStep = now;
    digitalWrite(btnLedArray[3], LOW);
    randomSeed(analogRead(2));
    gameStepBtn = random(0,5);
    gameStepLength = random(3000/gameLevel, 5000/gameLevel);
    digitalWrite(btnLedArray[gameStepBtn], HIGH);
  }

  if ((now - previousMillisGameStep >= gameStepLength) || (presses > 1) || (presses == 1 && !btnPressed[gameStepBtn])) {
    // GAME OVER
    playSound(fx2Trigger);
    wackAMoleState = gameOver;
    previousMillisGameStep = 0;
    for (int i=0;i<5;i++) analogWrite(btnLedArray[i], 255);
    for (int b=255;b>0;b--) {
      for (int i=0;i<5;i++) analogWrite(btnLedArray[i], b);
      delay(10);
    }
    for (int i=0;i<5;i++) analogWrite(btnLedArray[i], 0);
    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[0] && !btnPressed[1] && !btnPressed[2] && !btnPressed[3] && !btnPressed[4]);
    matrix1.print(0); matrix1.writeDisplay();
    wackAMoleState = waitForStart;
  }
  else if (btnPressed[gameStepBtn] && presses == 1) {
    digitalWrite(btnLedArray[gameStepBtn], LOW);
    int counter = 0;
    do { delay(1); checkButtonInputs(); counter++; }
    while (counter < 1000 && btnPressed[gameStepBtn]);
    previousMillisGameStep = now;
    int temp;
    do { temp = random(0,5); gameStepLength = random(3000/gameLevel, 5000/gameLevel); }
    while (gameStepBtn == temp);
    gameStepBtn = temp;
    digitalWrite(btnLedArray[gameStepBtn], HIGH);
    currentScore++;
    matrix1.print(currentScore); matrix1.writeDisplay();
    if (currentScore > highScore) { matrix2.print(currentScore); matrix2.writeDisplay(); }
  }
}

void ledBlinkStart() {
  unsigned long now = millis();
  if (now - previousMillisLedBlink >= intervalLedBlink) {
    previousMillisLedBlink = now;
    ledState[0] = !ledState[0];
    digitalWrite(btnLedArray[3], ledState[0]);
  }
}

void startGame() {
  unsigned long now = millis();
  digitalWrite(btnLedArray[3], 0);
  currentScore = 0;
  if (gameStartCountDown == 0) {
    playSound(fx3Trigger);
    previousMillisGameStarting = millis();
    gameStartCountDown = 4;
    delay(300);
    matrix1.print(gameStartCountDown, DEC); matrix1.writeDisplay();
  }
  if (now - previousMillisGameStarting >= intervalCountDown) {
    previousMillisGameStarting = now;
    if (gameStartCountDown > 0) {
      gameStartCountDown--;
      matrix1.print(gameStartCountDown, DEC); matrix1.writeDisplay();
      if (gameStartCountDown == 0) wackAMoleState = running;
    }
  }
}

void initializeSystem() {
  for (int i=0;i<5;i++) { digitalWrite(btnLedArray[i], HIGH); delay(75); }
  delay(1000);
  for (int i=4;i>=0;i--) { digitalWrite(btnLedArray[i], LOW); delay(75); }
  delay(1000);
  wackAMoleState = waitForStart;
  initVolume();
  if (actualVolume > 0) enableAmpPower(true);
}

void checkButtonInputs() {
  static byte prev[5], curr[5];
  static long last;
  if (last + debounceTime > millis()) return;
  last = millis();
  for (int i=0;i<5;i++) {
    curr[i] = digitalRead(btnArray[i]);
    if (curr[i] != btnPressed[i]) {
      if (btnPressed[i] && !curr[i]) { if (debug) Serial.println("released "+String(i+1)); btnPressed[i]=0; }
      if (!btnPressed[i] && curr[i]) { if (debug) Serial.println("pressed "+String(i+1)); btnPressed[i]=1; }
    }
  }
}

void initVolume() {
  int target = analogRead(potmeterVolume)/30;
  while (actualVolume > target) { digitalWrite(fxVolumeArray[1],LOW); actualVolume--; delay(20); digitalWrite(fxVolumeArray[1],HIGH); delay(20); }
  while (actualVolume < target) { digitalWrite(fxVolumeArray[0],LOW); actualVolume++; delay(20); digitalWrite(fxVolumeArray[0],HIGH); delay(20); }
}

void readVolumePotmeter() {
  int target = analogRead(potmeterVolume)/30;
  if (actualVolume > target) { digitalWrite(fxVolumeArray[1],LOW); actualVolume--; delay(40); digitalWrite(fxVolumeArray[1],HIGH); if (actualVolume==0) enableAmpPower(false); }
  else if (actualVolume < target) { digitalWrite(fxVolumeArray[0],LOW); if (actualVolume==0) enableAmpPower(true); actualVolume++; delay(40); digitalWrite(fxVolumeArray[0],HIGH); }
}

void readGameLevelPotmeter() {
  int v = analogRead(potmeterGameLevel);
  if (v < 102) gameLevel=1; else if (v < 204) gameLevel=2; else if (v < 306) gameLevel=3;
  else if (v < 408) gameLevel=4; else if (v < 510) gameLevel=5; else if (v < 612) gameLevel=6;
  else if (v < 714) gameLevel=7; else if (v < 816) gameLevel=8; else if (v < 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();
  matrix2.print(highScore > -1 ? highScore : 0); matrix2.writeDisplay();
}

void playSound(int s) {
  if (currentPlayingSound != s) {
    for (int i=0;i<11;i++) digitalWrite(fxTriggerArray[i], HIGH);
    digitalWrite(fxTriggerArray[s], LOW);
    currentPlayingSound = s;
  }
}

void enableAmpPower(bool on) { digitalWrite(ampPower, on); }

CAD-Dateien & Gehäuse

Schaltplan

Siehe beiliegendes Schaltplan-Bild (PNG).

Herstellungsprozess

  1. Die richtigen Instrumentenknöpfe für Ihre Geräte auswählen
  2. Die richtigen Linsenkopfschrauben mit Innensechskant wählen: Ein praktischer Leitfaden
  3. Der Knopf: Vom antiken Verschluss zur modernen Innovation
  4. Bewegungsgesteuerter AWS IoT Button mit Raspberry Pi, PIR-Sensor und MQTT
  5. UnifiedWater v1 – Komplettes Arduino Wasserqualitäts-Sensorkit
  6. Portables Abstimmungssystem mit GSM-Anbindung (Mobile Vote Box)
  7. Den richtigen PCB-Prototyp-Hersteller wählen: Ein umfassender Leitfaden
  8. Optimale Sägegeschwindigkeit für Bandsägen wählen: Praktischer Leitfaden
  9. Die richtige Tauchpumpe wählen: Expertentipps & Hauptmerkmale
  10. Gründe für Vertikaldrehzentren in der Präzisionsbearbeitung