Crea el Clásico Juego Asteroids con Arduino Mega y Matriz LED MAX72XX
Componentes y Suministros
- Arduino Mega 2560 × 1
- Shield Driver MAX7219 MAXREFDES99# (Matriz LED 8×8) × 1
- Pulsadores 12mm (SparkFun) × 2 (Izquierda/Derecha)
- Buzzer Activo × 1
- Protoboard (genérica) × 1
Sobre este Proyecto
Implementación del clásico juego Asteroids en una matriz LED 8×8 controlada por MAX7219. Controlas una nave (LED en fila inferior) moviéndola izquierda/derecha con dos pulsadores para esquivar asteroides que caen. La velocidad aumenta con el tiempo. Al chocar, muestra puntuación (ticks sobrevividos) en la matriz. Incluye sonido de explosión por buzzer.
Hardware y Conexiones
| Componente | Pin Arduino Mega |
|---|---|
| MAX7219 DIN (DataIn) | 12 |
| MAX7219 CLK | 11 |
| MAX7219 CS (LOAD) | 10 |
| Pulsador Izquierda | 2 (INT0, INPUT_PULLUP) |
| Pulsador Derecha | 3 (INT1, INPUT_PULLUP) |
| Buzzer | 9 (PWM) |
Alimentación: MAX7219 VCC→5V, GND→GND. Pulsadores: un terminal a pin, otro a GND (pull-up interno). Buzzer: + a pin 9, - a GND.
Lógica del Juego
- Nave: 1 LED en fila 7 (índice 7), columna
ship(0-7). - Asteroides: Array
columns[8]= fila actual de cada columna (0=vacío, 1-9=caendo, 10=fuera). - Bucle principal (tick): Cada
tickms (inicial 300ms, reduce 2% cada 4 ticks). - Spawn: Cada 4 ticks, columna aleatoria 0-7: si vacía, crea asteroide en fila 1.
- Caída: Cada tick, incrementa fila de asteroides activos. Si llega a 10 → borrar.
- Colisión: Si
columns[ship] == 9 or 10(asteroide en fila 8 o 9) → Game Over. - Puntuación: 1 punto por tick sobrevivido. Muestra dígitos en matriz (0-99, o >99 muestra centenas como puntos en fila superior).
- Reinicio: Cualquier pulsador tras Game Over →
setup()de nuevo.
Código Completo
/*********************************************************
* Asteroids en matriz MAX72XX 8x8
* (c) 2018 Joshua Weßner
*********************************************************/
#include <LedControl.h>
// Pines: DIN=12, CLK=11, LOAD=10, 1 dispositivo
LedControl lc = LedControl(12, 11, 10, 1);
// Variables globales
unsigned long delaytime = 1000;
int score = 0;
int tick = 300;
int tickCounter = 1;
int ship = 3; // Posición inicial nave (col 3)
int columns[8] = {0}; // Filas de asteroides por columna
unsigned long now;
unsigned long buttonPressed = 0;
int buttonDelay = 150; // Anti-rebote
volatile bool gameOver = false;
int pinLeft = 2, pinRight = 3;
void setup() {
gameOver = false; score = 0; tick = 300; tickCounter = 1; ship = 3;
now = millis(); buttonPressed = millis();
randomSeed(analogRead(A15)); // Ruido analógico para aleatoriedad
for (int i=0; i<8; i++) columns[i] = 0;
lc.shutdown(0, false); // Despertar MAX72XX
lc.setIntensity(0, 1); // Brillo medio (0-15)
lc.clearDisplay(0);
pinMode(pinLeft, INPUT_PULLUP);
pinMode(pinRight, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinLeft), leftISR, FALLING);
attachInterrupt(digitalPinToInterrupt(pinRight), rightISR, FALLING);
}
// ISR izquierda
void leftISR() {
if (millis() - buttonPressed > buttonDelay) {
if (ship != 0) ship--; else ship = 7; // Wrap-around
lc.clearDisplay(0);
buttonPressed = millis();
}
if (gameOver) { gameOver = false; setup(); }
}
// ISR derecha
void rightISR() {
if (millis() - buttonPressed > buttonDelay) {
if (ship != 7) ship++; else ship = 0;
lc.clearDisplay(0);
buttonPressed = millis();
}
if (gameOver) { gameOver = false; setup(); }
}
void loop() {
if (millis() - now > tick) { // Cada tick
score++; now = millis();
if (tickCounter == 1) { // Cada 4 ticks
tick = tick / 1.02; // Acelerar
int r = random(0, 8);
if (columns[r] == 0) columns[r] = 1; // Spawn
}
tickCounter = (tickCounter == 4) ? 1 : tickCounter + 1;
// Mover asteroides
for (int i=0; i<8; i++) {
if (columns[i] == 10) columns[i] = 0;
if (columns[i] != 0) columns[i]++;
}
lc.clearDisplay(0);
}
// Dibujar nave (fila 7)
lc.setLed(0, 7, ship, true);
// Dibujar asteroides (2 LEDs por asteroide para tamaño)
for (int i=0; i<8; i++) {
if (columns[i] > 0) {
lc.setLed(0, columns[i]-2, i, true);
lc.setLed(0, columns[i]-3, i, true);
}
}
// Colisión: asteroide en fila 8 (9) o 9 (10) en columna nave
if (columns[ship] == 10 || columns[ship] == 9) {
lc.clearDisplay(0);
// Animación explosión + sonido
for (int i=0; i<4; i++) {
lc.setLed(0, 7, ship+i, true);
lc.setLed(0, 7, ship-i, true);
lc.setLed(0, 7-i, ship+i, true);
lc.setLed(0, 7-i, ship-i, true);
lc.setLed(0, 7-1.5*i, ship, true);
unsigned long t = millis(); int rs = 1000;
while (millis() - t <= 250) {
rs--; tone(9, random(rs, 1000));
}
lc.clearDisplay(0); noTone(9);
}
delay(500);
// Mostrar puntuación
String s = String(score);
char d0 = s.length()>2 ? s[0] : ' '; // Centenas
char d1 = s.length()>1 ? s[s.length()-2] : (s.length()==1 ? '0' : s[0]);
char d2 = s[s.length()-1];
auto drawDigit = [&](char c, int pos) {
byte patterns[10][3] = {
{B00011111,B00010001,B00011111}, // 0
{B00001000,B00011111,B00000000}, // 1
{B00010111,B00010101,B00011101}, // 2
{B00010001,B00010101,B00011111}, // 3
{B00011100,B00000100,B00011111}, // 4
{B00011101,B00010101,B00010111}, // 5
{B00011111,B00010101,B00010111}, // 6
{B00010000,B00010011,B00011100}, // 7
{B00011111,B00010101,B00011111}, // 8
{B00011101,B00010101,B00011111} // 9
};
if (c>='0' && c<='9') {
int idx = c-'0';
lc.setColumn(0, pos, patterns[idx][0]);
lc.setColumn(0, pos+1, patterns[idx][1]);
lc.setColumn(0, pos+2, patterns[idx][2]);
}
};
if (score < 100) {
drawDigit(d1, 1); drawDigit(d2, 5);
} else {
drawDigit(d1, 1); drawDigit(d2, 5);
// Centenas como puntos en fila 0-1
int h = d0 - '0';
for (int i=1; i<=h; i++) {
lc.setLed(0,0,i-1,true); lc.setLed(0,1,i-1,true); delay(200);
}
}
gameOver = true;
while (gameOver) { /* espera botón */ }
}
}
Nota: El código original usa funciones draw0()..draw9() separadas; aquí se condensa con lambda para brevedad. La versión completa está en la sección "Code".
Librería Requerida
LedControl de Eberhard Fahle: GitHub – Instalar desde Gestor de Librerías.
Esquemático
Ver sección "Schematics" para diagrama Fritzing de conexiones.
Ideas de Expansión
- Añadir más matrices en cascada (MAX7219 soporta hasta 8) para área de juego mayor.
- Implementar disparos (tercer botón).
- Niveles, power-ups, high-score en EEPROM.
- Usar matriz 8×32 (4 módulos) para versión "arcade" real.
Proceso de manufactura
- Ajedrez: de sus orígenes antiguos a la fabricación moderna — una visión experta
- Pinball: Historia, Diseño y Fabricación de un Juego Arcade Clásico
- La Evolución y Artesanía del Fútbol Americano: De Juegos Ancestrales a Estándares NFL Modernos
- Construya el clásico juego Pong en Arduino UNO con pantalla OLED: Tutorial paso a paso
- Construye tu Propio Juego de Ruleta de 37 LEDs con Arduino Nano
- Construye una consola Pong 24×16 LED con Arduino Nano y MAX7219
- Construye un juego Tetris con Arduino Nano en matriz LED 16x8 DIY
- Juego interactivo con joystick analógico y LEDs en Arduino
- Pantalla LED Matricial Interactiva en Puerta con Sensor PIR - Saludo Navideño Arduino
- Pantalla de 8 LED activada por sonido con Arduino
- Construye un Robot Cuadrúpedo Inteligente con Arduino: Guía Paso a Paso