Pixel Chaser: Interaktives One-Tap-LED-Spiel mit Arduino Nano
Komponenten und Zubehör
| Komponente | Menge | Hinweis |
|---|---|---|
| Arduino Nano R3 | 1 | Beliebiger µC mit 2 freien IOs |
| Adafruit NeoPixel Ring: WS2812 5050 RGB LED (24 LEDs) | 1 | Ring oder Strip |
| Steckbrett (Halbgröße) | 1 | |
| Widerstand 10 kΩ | 1 | Pull-Down für Taster |
| Taster 12 mm (SparkFun) | 1 | Eingabe |
| Steckdrähte (Jumper Wires) | 1 Set |
Apps und Online-Dienste
- Arduino IDE
Projektbeschreibung
Als ehemaliger Game-Developer kenne ich den „Heiligen Gral“ der Mobile-Games: das perfekte „One-Tap“-Spiel. Ich wollte testen, ob sich ein cooles One-Click-„Physics“-Spiel mit Mikrocontroller, einem Button und visueller Rückmeldung realisieren lässt.
Vorstellung: PIXEL CHASER!
Einfacher Bau – los geht's!
Benötigte Teile
- Arduino Nano (oder beliebiger µC mit 2 freien I/O-Pins)
- RGB „NeoPixel“ Ring oder Strip
- Taster (Momentan)
- 10 kΩ Widerstand
- Steckbrett(e)
- Drähte
Schritt 1: Nano platzieren
Nano an einem Ende des Steckbretts, USB-Buchse am Rand.
Schritt 2: Taster platzieren
Am anderen Ende, nah am Rand für gute Erreichbarkeit.
Schritt 3: Pull-Down-Widerstand
10 kΩ zwischen einer Taster-Seite und GND-Schiene. Definiert LOW-Zustand. Verhindert Kurzschluss VCC-GND beim Drücken.
Schritt 4: VCC an Taster
Draht von der anderen Taster-Seite zur VCC-Schiene. Taster geht auf HIGH beim Drücken.
Schritt 5: Taster an Nano
Draht von GND-Seite des Tasters zu D3 am Nano. D3 liest Taster-Zustand.
Schritt 6: NeoPixel anschließen
VCC → VCC-Schiene, GND → GND-Schiene, DI (Data In) → D4 am Nano.
Schritt 7: Stromversorgung Nano → Breadboard
5V-Pin Nano → VCC-Schiene, GND-Pin Nano → GND-Schiene.
Schritt 8: Code hochladen & spielen!
Viel Spaß! Mehr Projekte auf meinem YouTube-Kanal.
Folge mir:
- Twitter: @unexpectedmaker
- Facebook: unexpectedmaker
- Instagram: unexpectedmaker
- Patreon: unexpectedmaker
- Tindie Shop: seonr
Code
Pixel Chaser Game – Arduino Code
/* ---------------------------------------------------------------------------
Pixel Chaser Game - v1.0.0 - 24/03/2019
AUTHOR/LICENSE: Seon Rozenblum - seon@unexpectedmaker.com
Copyright 2016, License: GNU GPL v3
https://www.gnu.org/licenses/gpl-3.0.html
LINKS: Blog: unexpectedmaker.com | YouTube: youtube.com/c/unexpectedmaker
DISCLAIMER: "as is", no support, no warranty.
PURPOSE: One-tap game on NeoPixel ring with single button.
--------------------------------------------------------------------------- */
#include <Adafruit_NeoPixel.h>
#include "OneButton.h"
#define PIXELPIN 4
#define NUMPIXELS 24
#define BUTTON_TAP 3
OneButton buttonTAP(BUTTON_TAP, false); // LOW = nicht gedrückt
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIXELPIN, NEO_GRB + NEO_KHZ800);
int playerIndex = -1, playerIndexTrail = -1, playerDirection = 1;
float nextMove = 0, currentPlayerSpeed = 150;
unsigned long countdown = 0;
int enemyIndex = -1, coinIndex = -1;
int score = 0, bestScore = 0, lastScore = 0;
bool gameOver = false;
void setup() {
pinMode(BUTTON_TAP, INPUT);
buttonTAP.attachClick(singleClick);
buttonTAP.attachLongPressStart(longClick);
pixels.begin();
pixels.setBrightness(20); // 20% Helligkeit
countdown = millis() + 2000; // 2 Sek. Countdown
}
void loop() {
buttonTAP.tick();
if (gameOver) return;
SetLevel();
if (countdown > millis()) { pixels.show(); return; }
DisplayPlayer();
pixels.show();
}
void ClearLevel() {
for(int i=0;i<NUMPIXELS;i++) pixels.setPixelColor(i, pixels.Color(0,0,0));
pixels.show();
}
void BestScore() {
for(int i=0;i<NUMPIXELS;i++) {
pixels.setPixelColor(i, i<bestScore ? pixels.Color(255,155,0) : pixels.Color(0,0,0));
}
if (lastScore < bestScore) {
for(int i=0;i<lastScore;i++) pixels.setPixelColor(i, pixels.Color(255,0,0));
}
pixels.show();
}
void GameOver() {
// Animation: Rot vom Enemy aus ausbreiten
int a=enemyIndex, b=enemyIndex;
for(int i=0;i<NUMPIXELS/2;i++) {
pixels.setPixelColor(a, pixels.Color(255,0,0));
pixels.setPixelColor(b, pixels.Color(255,0,0));
a=(a+1)%NUMPIXELS; b--; if(b==-1) b=NUMPIXELS;
pixels.show(); delay(20);
}
delay(100);
// Zurücksetzen
a=enemyIndex; b=enemyIndex;
for(int i=0;i<NUMPIXELS/2;i++) {
pixels.setPixelColor(a, pixels.Color(0,0,0));
pixels.setPixelColor(b, pixels.Color(0,0,0));
a=(a+1)%NUMPIXELS; b--; if(b==-1) b=NUMPIXELS;
pixels.show(); delay(20);
}
delay(100); BestScore();
}
void SetLevel() {
if (enemyIndex < 0) {
if (playerIndex < 0) enemyIndex = NUMPIXELS / 2;
else {
enemyIndex = random(0, NUMPIXELS);
while (abs(enemyIndex - playerIndex) < NUMPIXELS/4) enemyIndex = random(0, NUMPIXELS);
}
}
if (coinIndex < 0) {
coinIndex = random(0, NUMPIXELS);
while (abs(coinIndex - playerIndex) < 7 || abs(coinIndex - enemyIndex) < 7) coinIndex = random(0, NUMPIXELS);
}
pixels.setPixelColor(enemyIndex, pixels.Color(255,0,0)); // Rot = Feind
pixels.setPixelColor(coinIndex, pixels.Color(255,255,0)); // Gelb = Münze
}
void DisplayPlayer() {
if (nextMove < millis()) {
nextMove = millis() + currentPlayerSpeed;
// Trail aktualisieren
if (playerIndexTrail >= 0) pixels.setPixelColor(playerIndexTrail, pixels.Color(0,0,0));
if (playerIndex >= 0) {
pixels.setPixelColor(playerIndex, pixels.Color(0,100,0)); // Trail grün dunkel
playerIndexTrail = playerIndex;
}
// Spieler bewegen
playerIndex += playerDirection;
if (playerIndex < 0) playerIndex = NUMPIXELS - 1;
else if (playerIndex == NUMPIXELS) playerIndex = 0;
pixels.setPixelColor(playerIndex, pixels.Color(0,255,0)); // Spieler hellgrün
// Münze eingesammelt?
if (playerIndex == coinIndex) {
enemyIndex = -1; coinIndex = -1; score++;
currentPlayerSpeed = constrain(currentPlayerSpeed - 10, 50, 150); // Schneller
ClearLevel();
pixels.setPixelColor(playerIndex, pixels.Color(0,255,0));
}
// Feind getroffen?
else if (playerIndex == enemyIndex) {
lastScore = score;
if (score >= bestScore) bestScore = score;
GameOver();
gameOver = true;
enemyIndex = -1; coinIndex = -1; playerIndex = -1;
}
}
}
void singleClick() {
if (countdown > millis()) return; // Noch Countdown
playerDirection = -playerDirection; // Richtung umkehren
}
void longClick() {
gameOver = !gameOver; // Toggle Game Over
if (gameOver) { // Spiel abbrechen
enemyIndex = -1; coinIndex = -1; playerIndex = -1;
currentPlayerSpeed = 150; ClearLevel();
} else { // Neues Spiel starten
ClearLevel(); score = 0; currentPlayerSpeed = 150;
countdown = millis() + 2000;
}
}
Herstellungsprozess
- Echtzeit-Gyroskop-Spiel mit Arduino Nano & MPU-6050
- Arduino Digitaler Würfel: LCD-Würfel mit Zufallszahlen (1–6)
- Klassisches Pong-Spiel auf Arduino UNO mit OLED-Display bauen – Schritt-für-Schritt-Tutorial
- 37-LED-Roulette-Spiel mit Arduino Nano bauen – Europäisches Layout
- DIY Arduino USB Gaming Controller – Bauen Sie Ihren eigenen High-Performance Gamepad
- Arduino Touch Breakout-Spiel: Klassisches Arcade auf 2,4″ TFT LCD
- Tetris-Spiel mit Arduino Nano auf selbstgebauter 16×8 LED-Matrix
- Arduino-basierte abstoßende Magnetschwebung: Einfache Schaltung & DIY-Anleitung
- Arduino-gesteuertes automatisiertes Chrome Dino-Spiel bauen
- Alexa-fähiger Arduino Home Controller: Smarte Automatisierung leicht gemacht