Consola Arcade

GRUPO 19

Formado por los integrantes:

  • Miguel Regato Herrero
  • Alberto Jesús García Guerra

ÍNDICE

  1. Introducción
  2. Componentes hardware
  3. Coste
  4. Circuito
  5. Código
  6. Pasos seguidos
  7. Problemas durante la realización
  8. Demostración
  9. 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

COMPONENTESPRECIO
Arduino Uno0€
Protoboard0€
Joystick0€
Buzzer0€
Cables y resistencias0€
Pantalla LCD con I2C3.82€
Botones LED arcade11.99€
Caja de plástico3.6€
Terminales faston hembra2.5€
Pintura y materiales para el montaje0€
TOTAL21.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.

Circuito con los componentes

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.

Prueba juego Simón Dice

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.

Caja antes del proceso de fabricación
Marcas para cortar la tapa
Agujeros para los componentes
Primera capa de pintura

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.

Botones LED arcade
Pantalla LCD con adaptador

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.

Montaje de botones y pantalla
Cableado de todos los componentes

6. Implementación de los juegos

Una vez confirmamos que todos los componentes funcionaban correctamente, procedimos a implementar el código de la consola.

Todos los componentes funcionando

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.

También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *