#include <Adafruit_NeoPixel.h>
#include <Keypad.h>
#define PIN_NEO_PIXEL 13
#define NUM_PIXELS 64
#define ROW1 8
#define ROW2 9
#define ROW3 10
#define ROW4 11
#define COL1 A0 // A0 es PC0
#define COL2 A1 // A1 es PC1
#define COL3 A2 // A2 es PC2
#define COL4 A3 // A3 es PC3
#define CONF 0
#define PLAY 1
#define OVER 2
Adafruit_NeoPixel NeoPixel(NUM_PIXELS, PIN_NEO_PIXEL, NEO_GRB + NEO_KHZ800);
// Variables del juego
int posPaddleX = 3; //Posición de la paleta
int posPaddleY = 7;
int posBallX = 3; //Posición de la bola
int posBallY = 6;
int dirBallX = 1; //Dirección de la bola
int dirBallY = -1;
int state = CONF;
int velocidadJuego;
const uint8_t face[8] = {
// Cara de perdida
B00000000,
B10100101,
B01000010,
B10100101,
B00000000,
B01111110,
B10000001,
B00000000
};
const uint8_t levels[9][8] = {
{ // Nivel 1
B00000000,
B01000100,
B01001100,
B01000100,
B01000100,
B01101110,
B00000000,
B00000000
},
{ // Nivel 2
B00000000,
B01001110,
B01000010,
B01001110,
B01001000,
B01101110,
B00000000,
B00000000
},
{ // Nivel 3
B00000000,
B01001110,
B01000010,
B01001110,
B01000010,
B01101110,
B00000000,
B00000000
},
{ // Nivel 4
B00000000,
B01001010,
B01001010,
B01001110,
B01000010,
B01100010,
B00000000,
B00000000
},
{ // Nivel 5
B00000000,
B01001110,
B01001000,
B01001110,
B01000010,
B01101110,
B00000000,
B00000000
},
{ // Nivel 6
B00000000,
B01001110,
B01001000,
B01001110,
B01001010,
B01101110,
B00000000,
B00000000
},
{ // Nivel 7
B00000000,
B01001110,
B01000010,
B01000100,
B01001000,
B01101000,
B00000000,
B00000000
},
{ // Nivel 8
B00000000,
B01001110,
B01001010,
B01001110,
B01001010,
B01101110,
B00000000,
B00000000
},
{ // Nivel 9
B00000000,
B01001110,
B01001010,
B01001110,
B01000010,
B01101110,
B00000000,
B00000000
}
};
void displayFace() {
NeoPixel.clear(); //Permite borrar cualquier estado anterior
for (int r = 0; r < 8; r++) { // bucles "for" los cuales recorren filas y columnas
for (int c = 0; c < 8; c++) {
if (bitRead(face[r], 7 - c)) { // selecciona el byte correspondiente a la fila actual de la matriz
NeoPixel.setPixelColor(r * 8 + c, NeoPixel.Color(255, 0, 0));
}
}
}
NeoPixel.show(); // Muestra los pixeles en el hardware
}
void displayLevelSelection(int level) {
NeoPixel.clear();
for (int r = 0; r < 8; r++) {
for (int c = 0; c < 8; c++) {
if (bitRead(levels[level - 1][r], 7 - c)) {
NeoPixel.setPixelColor(r * 8 + c, NeoPixel.Color(255, 0, 0));
}
}
}
NeoPixel.show(); // Muestra los pixeles
}
void displayGame() {
NeoPixel.clear();
// Display paddle
NeoPixel.setPixelColor(posPaddleY * 8 + posPaddleX, NeoPixel.Color(0, 0, 255));
NeoPixel.setPixelColor(posPaddleY * 8 + posPaddleX + 1, NeoPixel.Color(0, 0, 255));
// Display ball
NeoPixel.setPixelColor(posBallY * 8 + posBallX, NeoPixel.Color(0, 255, 0));
NeoPixel.show();
}
int updateBall() {
posBallX += dirBallX;
posBallY += dirBallY;
// Collision with left & right walls
if (posBallX < 0) {
posBallX = 0;
dirBallX = 1;
}
if (posBallX > 7) {
posBallX = 7;
dirBallX = -1;
}
// Collision with top wall
if (posBallY < 0) {
posBallY = 0;
dirBallY = 1;
}
// Check if collision with paddle
if (posBallY == 7) {
if ((posBallX >= posPaddleX) && (posBallX <= posPaddleX + 1)) {
posBallY = 6;
dirBallY = -1;
} else {
return 1; // Ball missed paddle
}
}
return 0; // Ball did not miss paddle
}
void reiniciarJuego() {
posPaddleX = 3;
posBallX = 3;
posBallY = 6;
dirBallX = 1;
dirBallY = -1;
}
void setup() {
Serial.begin(115200);
NeoPixel.begin();
// Configurar pines 8 a 11 como salidas (PORTB)
DDRB |= B00001111;
// Configurar pines A0 a A3 como entradas con pull-up (PORTD)
DDRC &= B11110000;
PORTC |= B00001111;
}
char readKeypad() {
char key = 0;
for (int row = 0; row < 4; row++) {
// Establece la fila actual en bajo y todas las demás en alto
PORTB = ~(1 << row);
// Comprueba cada columna en la fila actual
if (!(PINC & 0x01)) key = row == 0 ? '1' : row == 1 ? '4' : row == 2 ? '7' : '*';
if (!(PINC & 0x02)) key = row == 0 ? '2' : row == 1 ? '5' : row == 2 ? '8' : '0';
if (!(PINC & 0x04)) key = row == 0 ? '3' : row == 1 ? '6' : row == 2 ? '9' : '#';
if (!(PINC & 0x08)) key = row == 0 ? 'A' : row == 1 ? 'B' : row == 2 ? 'C' : 'D';
// Si se encuentra una tecla, rompe el bucle
if (key != 0) break;
}
// Restablece las filas a su estado inicial
PORTB = 0x0F;
return key;
}
void loop() {
char key = readKeypad();
if (state == CONF) {
// Si estamos en modo de configuración
if (key >= '1' && key <= '9') {
int nivel = key - '0';
displayLevelSelection(nivel); // Muestra el nivel seleccionado
velocidadJuego = 110 - (nivel * 10); // Cálculo de velocidad
} else if (key == '0') {
state = PLAY;
}
}
else if (state == PLAY) {
// Lógica del juego
displayGame();
if (updateBall()) {
displayFace();
Serial.println("Perdió");
state = OVER;
}
}
else if (state == OVER) {
if (key == 'D') {
// Reiniciar el juego con la tecla 'D'
reiniciarJuego();
NeoPixel.clear();
NeoPixel.show();
state = CONF;
}
}
if (key == '*') {
// Mueve la paleta a la izquierda
if (posPaddleX > 0) posPaddleX--;
} else if (key == '#') {
// Mueve la paleta a la derecha
if (posPaddleX < 6) posPaddleX++;
}
delay(velocidadJuego); // Controlar la velocidad del juego
}