Consola Arcade
GRUPO 19
Formado por los integrantes:
- Miguel Regato Herrero
- Alberto Jesús García Guerra
ÍNDICE
- Introducción
- Componentes hardware
- Coste
- Circuito
- Código
- Pasos seguidos
- Problemas durante la realización
- Demostración
- Conclusión
1. INTRODUCCIÓN
En este proyecto, hemos desarrollado una máquina arcade con varios minijuegos, diseñada para ofrecer diversión y entretenimiento tanto para jugar solo como en compañía de amigos. Además, gracias a su caja, es portátil, lo que permite llevar la diversión a cualquier lugar. A lo largo de este post detallaremos el proceso de diseño, construcción y programación, así como los diferentes minijuegos que incluye y las tecnologías utilizadas para su desarrollo, incluyendo hardware y software.
2. COMPONENTES HARDWARE
- Pantalla
- Joystick
- Botones LED arcade
- Buzzer
- Arduino Uno
- Protoboard
- Pila 9V
- Cables y resistencias
- Caja de plástico
- Terminales faston hembra
3. COSTE
COMPONENTES | PRECIO |
Arduino Uno | 0€ |
Protoboard | 0€ |
Joystick | 0€ |
Buzzer | 0€ |
Cables y resistencias | 0€ |
Pantalla LCD con I2C | 3.82€ |
Botones LED arcade | 11.99€ |
Caja de plástico | 3.6€ |
Terminales faston hembra | 2.5€ |
Pintura y materiales para el montaje | 0€ |
TOTAL | 21.91€ |
4. CIRCUITO
A continuación, se mostrará un diagrama de la conexión de los componentes. Es importante tener en cuenta que, debido a las limitaciones de la herramienta, los botones LED y el joystick se representarán de manera simplificada. En el diagrama, los botones se muestran separados por un LED y un botón cada uno, aunque en el componente real estos estarán unidos. En cuanto al joystick, se ha insertado un componente negro redondo para simular su utilización.
5. CÓDIGO
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // Inicialización de la pantalla LED
// Definir los pines para el joystick, los botones y el zumbador
const int pinJoystickX = A0;
const int pinJoystickY = A1;
const int pinBotonAmarillo = 2; // Botón amarillo
const int pinBotonVerde = 3; // Botón verde
const int pinBotonRojo = 4; // Botón rojo
const int pinBotonAzul = 5; // Botón azul
const int pinBuzzer = 6; // Zumbador
const int pinLedAmarillo = 7; // Led amarillo
const int pinLedVerde = 8; // Led verde
const int pinLedRojo = 9; // Led rojo
const int pinLedAzul = 10; // Led azul
// Melodía perdedor
const int melodia[] = {262, 196, 196, 220, 196, 0, 247, 262};
const int duracionNotas[] = {4, 8, 8, 4, 4, 4, 4, 4};
// Nivel máximo Simón Dice
const int NIVEL_MAX = 33;
int nivelActual = 1; // Variable para mantener el estado del juego actual
int secuencia[NIVEL_MAX];
int secuenciaUsuario[NIVEL_MAX];
void setup()
{
// Inicializar la pantalla LCD
lcd.init();
lcd.backlight();
delay(100);
// Mostrar mensaje de bienvenida
lcd.setCursor(0, 0);
lcd.print("Bienvenido");
delay(1000);
lcd.clear();
// Mostrar el juego 1 como predeterminado
lcd.setCursor(0, 0);
lcd.print("Escoge juego...");
lcd.setCursor(0, 1);
lcd.print("Simon dice");
// Configurar los botones y el zumbador como entrada/salida
pinMode(pinBotonAmarillo, INPUT_PULLUP);
pinMode(pinBotonVerde, INPUT_PULLUP);
pinMode(pinBotonRojo, INPUT_PULLUP);
pinMode(pinBotonAzul, INPUT_PULLUP);
pinMode(pinBuzzer, OUTPUT);
pinMode(pinLedAmarillo, OUTPUT);
pinMode(pinLedVerde, OUTPUT);
pinMode(pinLedRojo, OUTPUT);
pinMode(pinLedAzul, OUTPUT);
}
void loop()
{
// Esperar a que el usuario mueva el joystick o presione un botón
while (true)
{
digitalWrite(pinLedAmarillo, HIGH);
int valY = analogRead(pinJoystickY);
int estadoBotonAmarillo = digitalRead(pinBotonAmarillo);
// Si se presiona el botón amarillo, entrar al menú del juego actual
if (estadoBotonAmarillo == LOW)
{
entraJuego();
break;
}
// Si el joystick se mueve hacia amarillo, pasar al siguiente juego
if (valY > 800)
{
nivelActual = (nivelActual % 3) + 1; // Cambiar al siguiente juego (1, 2 o 3)
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Escoge juego...");
lcd.setCursor(0, 1);
lcd.print(nombreJuego(nivelActual));
// break;
}
// Si el joystick se mueve hacia arriba, pasar al juego anterior
if (valY < 200)
{
nivelActual = (nivelActual - 2 + 3) % 3 + 1; // Cambiar al juego anterior (1, 2 o 3)
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Escoge juego...");
lcd.setCursor(0, 1);
lcd.print(nombreJuego(nivelActual));
// break;
}
delay(200); // Pequeña pausa para evitar el rebote
}
}
// Método para obtener el nombre del juego según su número
String nombreJuego(int numeroJuego) {
switch (numeroJuego) {
case 1:
return "Simon dice";
case 2:
return "Duelo a Reflejos";
case 3:
return "Adivina...";
default:
return "Desconocido";
}
}
// Método para entrar al menú del juego actual
void entraJuego() {
digitalWrite(pinLedAmarillo, HIGH);
switch (nivelActual) {
case 1:
apagarLeds();
playGame1();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Escoge juego...");
lcd.setCursor(0, 1);
lcd.print("Simon dice");
break;
case 2:
apagarLeds();
playGame2();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Escoge juego...");
lcd.setCursor(0, 1);
lcd.print("Duelo a Reflejos");
break;
case 3:
apagarLeds();
playGame3();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Escoge juego...");
lcd.setCursor(0, 1);
lcd.print("Adivina...");
break;
}
}
// Simón dice
void playGame1()
{
int secuencia[NIVEL_MAX];
int secuenciaUsuario[NIVEL_MAX];
int nivel = 0;
int longitudSecuencia = 0; // Longitud total de la secuencia
lcd.clear();
lcd.print("Jugando...");
while (true)
{
// Generar nueva secuencia
for (int i = longitudSecuencia; i <= nivel; ++i)
{
secuencia[i] = random(4); // Generar un número aleatorio entre 0 y 3
longitudSecuencia++;
}
delay(250);
// Mostrar la secuencia al usuario
for (int i = 0; i < longitudSecuencia; ++i)
{
switch (secuencia[i])
{
case 0:
digitalWrite(pinLedAmarillo, HIGH);
tone(pinBuzzer, 500, 100); // Pitido breve
delay(1000);
digitalWrite(pinLedAmarillo, LOW);
noTone(pinBuzzer); // Detener el tono
break;
case 1:
digitalWrite(pinLedVerde, HIGH);
tone(pinBuzzer, 600, 100); // Pitido breve
delay(1000);
digitalWrite(pinLedVerde, LOW);
noTone(pinBuzzer); // Detener el tono
break;
case 2:
digitalWrite(pinLedRojo, HIGH);
tone(pinBuzzer, 700, 100); // Pitido breve
delay(1000);
digitalWrite(pinLedRojo, LOW);
noTone(pinBuzzer); // Detener el tono
break;
case 3:
digitalWrite(pinLedAzul, HIGH);
tone(pinBuzzer, 800, 100); // Pitido breve
delay(1000);
digitalWrite(pinLedAzul, LOW);
noTone(pinBuzzer); // Detener el tono
break;
}
delay(500); // Esperar medio segundo antes de mostrar el siguiente LED
}
// Esperar un tiempo antes de que el usuario ingrese la secuencia
delay(100);
// Leer la secuencia del usuario
for (int i = 0; i < longitudSecuencia; ++i)
{
while (true)
{
bool botonPresionado = false;
if (digitalRead(pinBotonAmarillo) == LOW)
{
secuenciaUsuario[i] = 0;
digitalWrite(pinLedAmarillo, HIGH);
tone(pinBuzzer, 500, 100); // Pitido breve
delay(200);
digitalWrite(pinLedAmarillo, LOW);
noTone(pinBuzzer); // Detener el tono
botonPresionado = true;
}
else if (digitalRead(pinBotonVerde) == LOW)
{
secuenciaUsuario[i] = 1;
digitalWrite(pinLedVerde, HIGH);
tone(pinBuzzer, 600, 100); // Pitido breve
delay(200);
digitalWrite(pinLedVerde, LOW);
noTone(pinBuzzer); // Detener el tono
botonPresionado = true;
}
else if (digitalRead(pinBotonRojo) == LOW)
{
secuenciaUsuario[i] = 2;
digitalWrite(pinLedRojo, HIGH);
tone(pinBuzzer, 700, 100); // Pitido breve
delay(200);
digitalWrite(pinLedRojo, LOW);
noTone(pinBuzzer); // Detener el tono
botonPresionado = true;
}
else if (digitalRead(pinBotonAzul) == LOW)
{
secuenciaUsuario[i] = 3;
digitalWrite(pinLedAzul, HIGH);
tone(pinBuzzer, 800, 100); // Pitido breve
delay(200);
digitalWrite(pinLedAzul, LOW);
noTone(pinBuzzer); // Detener el tono
botonPresionado = true;
}
// Esperar a que el botón se suelte completamente
while (botonPresionado && (digitalRead(pinBotonAmarillo) == LOW || digitalRead(pinBotonVerde) == LOW ||
digitalRead(pinBotonRojo) == LOW || digitalRead(pinBotonAzul) == LOW))
;
if (botonPresionado)
break; // Si el botón ha sido presionado, salir del bucle
}
}
// Verificar la secuencia
bool secuenciaCorrecta = true;
for (int i = 0; i < longitudSecuencia; ++i)
{
if (secuencia[i] != secuenciaUsuario[i])
{
secuenciaCorrecta = false;
break;
}
}
if (secuenciaCorrecta)
{
nivel++;
}
else
{
// ¡Has perdido!
encenderLeds();
lcd.clear();
lcd.print("Has perdido!!");
lcd.setCursor(0, 1);
lcd.print("Total: " + String(nivel) + " rondas");
lcd.setCursor(0, 0);
delay(1000);
reproducirMelodia(); // Reproducir la melodía de la derrota
delay(2000);
lcd.clear();
lcd.write("Volviendo...");
apagarLeds();
return;
}
}
}
void reproducirMelodia()
{
for (int i = 0; i < 8; i++)
{
int duracionNota = 1000 / duracionNotas[i];
tone(pinBuzzer, melodia[i], duracionNotas);
int pausaEntreNotas = duracionNota * 1.30;
delay(pausaEntreNotas);
noTone(pinBuzzer);
}
}
// Duelo de reflejos
void playGame2() {
lcd.clear();
lcd.print("Preparados...");
delay(1000);
bool game_over = false;
int botonAzul = digitalRead(pinBotonAzul);
int botonVerde = digitalRead(pinBotonVerde);
digitalWrite(pinLedAzul, LOW); // apagamos ledes de jugadores
digitalWrite(pinLedVerde, LOW);
digitalWrite(pinLedRojo, HIGH); // Encendemos el led de salida
delay(random(5000) + 1000); // Tiempo aleatorio entre 1 y 10 segundos
lcd.clear();
digitalWrite(pinLedRojo, LOW); // Pistoletazo de salida
lcd.print("Adelante");
digitalWrite(pinLedAmarillo, HIGH);
while (!game_over) {
if ((digitalRead(pinBotonAzul) == LOW) && (!game_over)) { // Jugador 1 gana
digitalWrite(pinLedAzul, HIGH);
lcd.clear();
lcd.print("Gana Azul");
tone(pinBuzzer, 800, 100); // Pitido breve
delay(200);
noTone(pinBuzzer); // Detener el tono
game_over = true;
}
if ((digitalRead(pinBotonVerde) == LOW) && (!game_over)) { // Jugador 2 gana
digitalWrite(pinLedVerde, HIGH);
lcd.clear();
lcd.print("Gana verde");
tone(pinBuzzer, 600, 100); // Pitido breve
delay(200);
noTone(pinBuzzer); // Detener el tono
game_over = true;
}
}
digitalWrite(pinLedAmarillo, LOW);
victoria();
delay(3000);
apagarLeds();
lcd.clear();
delay(1000);
}
// Adivina el número
void playGame3()
{
lcd.clear();
lcd.print("Cargando...");
delay(1000);
lcd.clear();
randomSeed(analogRead(0));
int numeroAdivinar = random(1, 11);
int numeroSeleccionado = 1;
bool acabarJuego = false;
int intentosRestantes = 5;
while (!acabarJuego && intentosRestantes > 0)
{
int valY = analogRead(pinJoystickY);
int estadoBotonAmarillo = digitalRead(pinBotonAmarillo);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tu numero: ");
lcd.setCursor(0, 1);
lcd.print(numeroSeleccionado);
digitalWrite(pinLedAmarillo, HIGH);
if ((valY > 800) && (numeroSeleccionado > 1))
{
numeroSeleccionado--;
}
if ((valY < 350) && (numeroSeleccionado < 10))
{
numeroSeleccionado++;
}
if (estadoBotonAmarillo == LOW)
{
lcd.clear();
lcd.setCursor(0, 0);
if (numeroSeleccionado == numeroAdivinar)
{
lcd.print("Enhorabuena");
acabarJuego = true;
}
else
{
lcd.print("Incorrecto");
intentosRestantes--;
if (intentosRestantes > 0)
{
lcd.setCursor(0, 1);
if (numeroSeleccionado > numeroAdivinar)
{
lcd.print("Es menor que " + String(numeroSeleccionado));
}
else
{
lcd.print("Es mayor que " + String(numeroSeleccionado));
}
}
}
delay(1000);
}
delay(200);
}
// Encender todos los leds para indicar el Fin del juego
encenderLeds();
lcd.clear();
lcd.setCursor(0, 0);
if (intentosRestantes == 0)
{
lcd.print("Has perdido!!");
reproducirMelodia();
}
else
{
lcd.print("Has ganado!!!");
victoria();
}
delay(2000);
apagarLeds();
lcd.clear();
return;
}
void encenderLeds()
{
digitalWrite(pinLedAzul, HIGH);
digitalWrite(pinLedVerde, HIGH);
digitalWrite(pinLedRojo, HIGH);
digitalWrite(pinLedAmarillo, HIGH);
}
void apagarLeds()
{
digitalWrite(pinLedAzul, LOW);
digitalWrite(pinLedVerde, LOW);
digitalWrite(pinLedRojo, LOW);
digitalWrite(pinLedAmarillo, LOW);
}
void victoria()
{
tone(pinBuzzer, 800, 100);
delay(200);
noTone(pinBuzzer);
tone(pinBuzzer, 800, 100);
delay(200);
noTone(pinBuzzer);
tone(pinBuzzer, 800, 100);
delay(200);
noTone(pinBuzzer);
tone(pinBuzzer, 800, 100);
delay(200);
noTone(pinBuzzer);
}
6. PASOS SEGUIDOS
1. Planificar el proyecto
En primer lugar, decidimos planificar cómo queríamos que fuera el proyecto. Esto implicaba seleccionar qué minijuegos queríamos incluir y diseñar la estructura de la caja que simularía ser la consola.
2. Prueba de juegos a implementar
Antes de comenzar con el proyecto en sí, decidimos emular los minijuegos que la consola iba a incluir. Esto nos permitiría verificar cual iba a ser la funcionalidad y determinar los componentes de hardware finales que necesitaríamos. Esta fase inicial nos ayudó a probar diferentes enfoques y mecánicas de juego, así como de identificar cualquier problema que pudiera surgir durante el desarrollo, además de los componentes hardware necesarios para obtener los resultados deseados.
3. Fabricación de la caja
Para la realización de la consola, decidimos utilizar una caja de plástico, ya que nos ofrecía la posibilidad de abrirse para poder ocultar todo el hardware en su interior. Después de seleccionar la caja adecuada, procedimos a pintarla y crear los agujeros necesarios para poder insertar todos los componentes.
4. Compra de componentes
Una vez que tuvimos la caja preparada y conocíamos todos los componentes hardware necesarios, procedimos a comprarlos. Entre los componentes adquiridos se encontraban: una pantalla con adaptador que nos permitía utilizar menos pines de la placa de Arduino, botones con iluminación LED y terminales faston hembra que nos facilitaban la conexión de estos botones a la placa evitando que los cables se soltaran.
5. Montaje componentes
Una vez que los componentes llegaron, procedimos a montarlos en la caja de la consola. Durante este proceso, verificamos que todos los cables estuvieran correctamente conectados y que no hubiera posibilidad de cortocircuitos.
6. Implementación de los juegos
Una vez confirmamos que todos los componentes funcionaban correctamente, procedimos a implementar el código de la consola.
7. PROBLEMAS DURANTE LA REALIZACIÓN
- Número de pines de la placa Arduino Uno: Al contar con un número limitado de pines en la placa de Arduino y teniendo en cuenta que la pantalla LCD ocupaba la mayoría de ellos, teníamos un problema de espacio para conectar los demás componentes de la consola. Para resolver este problema, decidimos comprar otra pantalla LCD idéntica, pero esta vez con un adaptador I2C que reducía a dos la cantidad de pines necesarios para su conexión a la placa, lo que nos permitió liberar un número importante de pines para conectar el resto de componentes de la consola.
- Conexión de los cables y botones: En varias ocasiones, ocurrieron desconexiones debido a la forma de los propios cables, los cuales tendían a salirse de los pines de la placa de Arduino, especialmente cuando la consola estaba en movimiento. Esto provocaba que algunos componentes dejaran de funcionar temporalmente. Además, los botones tenían un método de conexión diferente a los demás componentes que dificultaba la conexión con los cables, complicando aún más el proceso de montaje. Para solucionar este problema, decidimos adquirir terminales faston hembra. Estos terminales proporcionaron una conexión mucho más segura y estable, garantizando que los cables permanecieran correctamente conectados incluso cuando la consola estaba en movimiento.
- Pintura y tamaño de los agujeros: Dado que no somos expertos en manualidades, al hacer los agujeros encontramos dificultades y estos quedaron un poco irregulares, ya que no teníamos los materiales adecuados para su elaboración. Por otra parte, la pintura no se adhería correctamente al plástico, por lo que se desprendía fácilmente, lo que nos obligó a aplicar varias capas adicionales para lograr el acabado deseado.
- Delay botones: En el juego del Simón Dice, nos dimos cuenta de que una vez que detectaba que se pulsaba un botón, no daba tiempo suficiente para que el usuario levantara el dedo y dejara de pulsar el botón. Esto provocaba que esa misma pulsación se registrara como una entrada para la siguiente ronda del juego, lo que generaba un mal funcionamiento en el flujo correcto del juego. Para solucionar este problema, tuvimos que añadir un fragmento de código que esperara a que el usuario dejara de pulsar el botón antes de continuar con la ejecución normal del juego. De esta manera, aseguramos que cada pulsación se registrara correctamente y que el juego funcionara según lo esperado.
- Delay joystick: Para utilizar el joystick, es necesario crear bucles que estén constantemente leyendo su estado para comprobar si se ha movido. Sin embargo, estos bucles deben incluir un retraso entre cada iteración. De lo contrario, se ejecutarían tan rápidamente que un solo movimiento del joystick sería detectado múltiples veces, lo que haría que fuera muy difícil de controlar. El problema con esta solución es que, durante este retraso, el proceso de ejecución se detiene. Por lo tanto, si mueves el joystick o pulsas un botón en ese momento, el sistema no lo detectará. Para solucionar esto, hemos introducido un valor de retraso lo suficientemente grande como para minimizar la probabilidad de que el sistema esté detenido cuando se realice alguna acción. Sin embargo, este valor no debe ser tan grande como para que la detección de los movimientos del joystick deje de ser precisa y cuente varios cambios como un solo movimiento del joystick.
8. DEMOSTRACIÓN
9. CONCLUSIÓN
Tras la finalización del proyecto, nos sentimos muy satisfechos con el resultado. Inicialmente, ninguno de los dos tenía conocimientos previos sobre Arduino, pero a lo largo de este proyecto hemos aprendido muchísimo. Esto nos ha hecho darnos cuenta de la infinidad de posibilidades que ofrece este área por lo que nos encantaría seguir aprendiendo y continuar realizando proyectos por nuestra cuenta.