Arduino Retro Gaming con una pantalla OLED

Arduino Retro Gaming con una pantalla OLED / Bricolaje

¿Alguna vez te has preguntado cuánto trabajo cuesta escribir tus propios juegos retro? ¿Qué tan fácil es Pong codificar para el Arduino? Únete a mí para mostrarte cómo construir una mini consola de juegos retro con Arduino y cómo codificar Pong desde cero. Aquí está el resultado final:

Plan de construcción

Este es un circuito bastante simple. UNA potenciómetro (pot) controlará el juego, y el Arduino controlará una pantalla OLED. Esto se producirá en una placa de pruebas, sin embargo, es posible que desee convertirlo en un circuito permanente e instalarlo en un estuche. Hemos escrito sobre cómo recrear Pong Cómo recrear el juego clásico de Pong con Arduino Cómo recrear el juego clásico de Pong con Arduino Pong fue el primer videojuego que llegó al mercado masivo. Por primera vez en la historia, el concepto de "videojuego" se introdujo en el hogar familiar, gracias a Atari 2600 -… Lea más antes, sin embargo, hoy les mostraré cómo escribir el código desde cero y cómo abajo cada parte.

Que necesitas

Esto es lo que necesitas:

  • 1 x Arduino (cualquier modelo)
  • 1 x 10k potenciómetro
  • 1 x 0.96 "Pantalla OLED I2C
  • 1 x Breadboard
  • Surtido macho> cables de conexión macho

DIYmall 0.96 "Ich I2c IIC Serial 128x64 Oled LCD LED módulo de pantalla blanca para Arduino 51 Msp420 Stim32 SCR DIYmall 0.96" Inch I2c IIC Serial 128x64 Oled LCD LED Módulo pantalla blanca para Arduino 51 Msp420 Stim32 SCR Compre ahora en Amazon $ 8.99

Cualquier Arduino debería funcionar, así que consulte nuestra guía de compras Guía de compras de Arduino: ¿Qué placa debería obtener? Guía de compra de Arduino: ¿Qué tabla debería obtener? Hay tantos tipos diferentes de tableros de Arduino por ahí que se te perdonará por estar confundido. ¿Qué debes comprar para tu proyecto? Déjanos ayudarte, con esta guía de compras de Arduino! Lea más si no está seguro de qué modelo comprar.

Estas pantallas OLED son muy interesantes. Por lo general, se pueden comprar en blanco, azul, amarillo o una mezcla de los tres. Existen a todo color, sin embargo, agregan un nivel completamente distinto a la complejidad y el costo de este proyecto..

El circuito

Este es un circuito bastante simple. Si no tienes mucha experiencia con Arduino, revisa estos proyectos para principiantes. 15 Grandes proyectos de Arduino para principiantes. 15 Grandes proyectos de Arduino para principiantes. ¿Interesado en Arduino pero no sabes por dónde empezar? ¡Aquí están algunos de nuestros mejores proyectos de Arduino para que comiencen los principiantes! Leer más primero.

Aquí está:

Mirando el frente de la olla, conecte el pin izquierdo a +5V y el pin derecho para suelo. Conecte el pin medio a pin analógico 0 (A0).

La pantalla OLED se conecta mediante el protocolo I2C. Conectar VCC y GND al arduino +5V y suelo. Conectar SCL a analógico cinco (A5). Conectar ASD a analógico 4 (A4). La razón por la que esto está conectado a los pines analógicos es simple; estos pines contienen los circuitos requeridos para el protocolo I2C. Asegúrese de que estén conectados correctamente, y que no estén cruzados. Los pines exactos variarán según el modelo, pero se utilizan A4 y A5 en el Nano y Uno. Consulte la documentación de la biblioteca de Wire para su modelo si no está usando un Arduino o Nano.

Prueba de olla

Cargue este código de prueba (asegúrese de seleccionar la placa y el puerto correctos de la Herramientas > Tablero y Herramientas > Puerto menús):

void setup () // ponga aquí su código de configuración, para ejecutarlo una vez: Serial.begin (9600); // configuración serial void loop () // ponga aquí su código principal, para ejecutar repetidamente: Serial.println (analogRead (A0)); // imprime el valor del retardo del pozo (500); 

Ahora abre el monitor serie (Parte superior derecha > Monitor de serie) y girar la olla. Debería ver el valor que se muestra en el monitor serie. Totalmente a la izquierda debe ser cero, y totalmente hacia la derecha debe ser 1023:

Ajustarás esto más adelante, pero por ahora está bien. Si no sucede nada o el valor cambia sin que usted haga nada, desconecte y vuelva a verificar el circuito.

Prueba OLED

La pantalla OLED es un poco más compleja de configurar. Necesita instalar dos bibliotecas para controlar la pantalla primero. Descargue las bibliotecas Adafruit_SSD1306 y Adafruit-GFX desde Github. Copie los archivos en su carpeta de bibliotecas. Esto varía dependiendo de su sistema operativo:

  • Mac OS: / Usuarios / Nombre de usuario / Documentos / Arduino / bibliotecas
  • Linux: / Inicio / Nombre de usuario / Sketchbook
  • Windows: / Usuarios / Arduino / Bibliotecas

Ahora sube un bosquejo de prueba. Ir Expediente > Ejemplos > Adafruit SSD1306 > ssd1306_128x64_i2c. Esto debería darle un gran boceto que contiene muchos gráficos:

Si no ocurre nada después de la carga, desconecte y vuelva a verificar sus conexiones. Si los ejemplos no están en los menús, es posible que deba reiniciar su IDE de Arduino.

El código

Ahora es el momento del código. Estaré explicando cada paso, así que salte al final si solo quiere que se ejecute. Esta es una buena cantidad de código, por lo que si no se siente seguro, consulte estos 10 recursos gratuitos. Aprenda a codificar: 10 recursos en línea gratuitos y fantásticos para perfeccionar sus habilidades Aprenda a codificar: 10 recursos en línea gratuitos y fantásticos para perfeccionar su Codificación de habilidades. Un tema que es evitado por muchos. Hay una gran cantidad de herramientas y recursos gratuitos, todos los cuales están disponibles en línea. Seguro que podrías tomar algunos cursos sobre el tema en un lugar cercano ... Lee más para aprender a codificar.

Comience por incluir las bibliotecas necesarias:

#incluir  #incluir  #incluir  #incluir 

SPI y CABLE Son dos bibliotecas de Arduino para manejar la comunicación I2C.. Adafruit_GFX y Adafruit_SSD1306 son las librerias que instalaste previamente.

A continuación, configure la pantalla:

Pantalla Adafruit_SSD1306 (4);

Luego configura todas las variables necesarias para ejecutar el juego:

resolución int [2] = 128, 64, bola [2] = 20, (resolución [1] / 2); const int PIXEL_SIZE = 8, WALL_WIDTH = 4, PADDLE_WIDTH = 4, BALL_SIZE = 4, SPEED = 3; int playerScore = 0, aiScore = 0, playerPos = 0, aiPos = 0; char ballDirectionHori = 'R', ballDirectionVerti = 'S'; boolean inProgress = true;

Estos almacenan todos los datos necesarios para ejecutar el juego. Algunos de estos almacenan la ubicación de la bola, el tamaño de la pantalla, la ubicación del jugador, etc. Observe cómo algunos de estos son const Es decir, son constantes, y nunca cambiarán. Esto permite que el compilador Arduino acelere un poco las cosas..

La resolución de la pantalla y la ubicación de la bola se almacenan en matrices. Las matrices son colecciones de cosas similares, y para la bola, almacena las coordenadas (X y Y). Acceder a los elementos en arreglos es fácil (no incluya este código en su archivo):

resolución [1];

Cuando los arreglos comienzan en cero, esto devolverá el segundo elemento en el arreglo de resolución (64). Actualizar elementos es aún más fácil (de nuevo, no incluya este código):

bola [1] = 15;

Dentro configuración del vacío (), configurar la pantalla:

void setup () display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.display (); 

La primera línea le dice a la biblioteca de Adafruit qué dimensiones y protocolo de comunicaciones está usando su pantalla (en este caso, 128 X 64 y I2C). La segunda línea (display.display ()) le dice a la pantalla que muestre lo que está almacenado en el búfer (que no es nada).

Crea dos métodos llamados DrawBall y borrarBall:

void drawBall (int x, int y) display.drawCircle (x, y, BALL_SIZE, WHITE);  void eraseBall (int x, int y) display.drawCircle (x, y, BALL_SIZE, BLACK); 

Estos toman la X y y Coordina la bola y dibújala en la pantalla utilizando el botón. círculo de dibujo Método de las bibliotecas de visualización. Esto usa la constante. BALL_SIZE definido anteriormente. Intenta cambiar esto y ver qué pasa. Este método drawCircle acepta un color de píxel. - NEGRO o BLANCO. Como se trata de una pantalla monocromática (un color), el blanco equivale a un píxel que está activado, y el negro desactiva el píxel.

Ahora crea un método llamado moverAi:

void moveAi () eraseAiPaddle (aiPos); if (ball [1]> aiPos) ++ aiPos;  else if (bola [1] < aiPos)  --aiPos;  drawAiPaddle(aiPos); 

Este método se encarga de mover el Inteligencia artificial o AI jugador. Este es un oponente informático bastante simple: si la pelota está por encima de la paleta, asciende. Si está debajo de la paleta, muévete hacia abajo. Bastante simple, pero funciona bien. Se utilizan los símbolos de incremento y decremento (++aiPos y -aiPos) para sumar o restar uno de la aiPosition. Puedes sumar o restar un número mayor para que la IA se mueva más rápido y, por lo tanto, ser más difícil de superar. Así es como harías eso:

aiPos + = 2;

Y:

aiPos - = 2;

los Más es igual y Menos iguales los signos son abreviados para sumar o restar dos de / al valor actual de aiPos. Aquí hay otra manera de hacer eso:

aiPos = aiPos + 2;

y

aiPos = aiPos - 1;

Observe cómo este método primero borra la paleta y luego la dibuja nuevamente. Esto tiene que hacerse así. Si se dibujara la nueva posición de la paleta, habría dos paletas superpuestas en la pantalla.

los dibujar Método utiliza dos bucles para dibujar la red:

void drawNet () for (int i = 0; i < (resolution[1] / WALL_WIDTH); ++i)  drawPixel(((resolution[0] / 2) - 1), i * (WALL_WIDTH) + (WALL_WIDTH * i), WALL_WIDTH);  

Esto usa el WALL_WIDTH variables para establecer su tamaño.

Crear métodos llamados drawPixels y borrarPixeles. Al igual que los métodos de bola, la única diferencia entre estos dos es el color de los píxeles:

void drawPixel (int posX, int posY, int dimensiones) para (int x = 0; x < dimensions; ++x)  for (int y = 0; y < dimensions; ++y)  display.drawPixel((posX + x), (posY + y), WHITE);    void erasePixel(int posX, int posY, int dimensions)  for (int x = 0; x < dimensions; ++x)  for (int y = 0; y < dimensions; ++y)  display.drawPixel((posX + x), (posY + y), BLACK);   

Nuevamente, ambos métodos usan dos para Bucles para dibujar un grupo de píxeles. En lugar de tener que dibujar cada píxel utilizando las bibliotecas drawPixel Método, los bucles dibujan un grupo de píxeles basados ​​en las dimensiones dadas.

los drawScore El método utiliza las características de texto de la biblioteca para escribir el jugador y la puntuación de AI en la pantalla. Estos se almacenan en playerScore y aiScore:

void drawScore () display.setTextSize (2); display.setTextColor (BLANCO); display.setCursor (45, 0); display.println (playerScore); display.setCursor (75, 0); display.println (aiScore); 

Este método también tiene un eraseScore Contraparte, que establece los píxeles en negro o apagado.

Los últimos cuatro métodos son muy similares. Dibujan y borran el jugador y las paletas de la IA:

void erasePlayerPaddle (int row) erasePixel (0, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); erasePixel (0, fila - PADDLE_WIDTH, PADDLE_WIDTH); erasePixel (0, fila, PADDLE_WIDTH); erasePixel (0, fila + PADDLE_WIDTH, PADDLE_WIDTH); erasePixel (0, fila + (PADDLE_WIDTH + 2), PADDLE_WIDTH); 

Observe cómo llaman a la borrarPixel Método de creación anterior. Estos métodos dibujan y borran la paleta apropiada..

Hay un poco más de lógica en el bucle principal. Aquí está el código completo:

#incluir  #incluir  #incluir  #incluir  Pantalla Adafruit_SSD1306 (4); resolución int [2] = 128, 64, bola [2] = 20, (resolución [1] / 2); const int PIXEL_SIZE = 8, WALL_WIDTH = 4, PADDLE_WIDTH = 4, BALL_SIZE = 4, SPEED = 3; int playerScore = 0, aiScore = 0, playerPos = 0, aiPos = 0; char ballDirectionHori = 'R', ballDirectionVerti = 'S'; boolean inProgress = true; void setup () display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.display ();  void loop () if (aiScore> 9 || playerScore> 9) // verifica el estado del juego inProgress = false;  if (inProgress) eraseScore (); eraseBall (bola [0], bola [1]); if (ballDirectionVerti == 'U') // mover bola hacia arriba en diagonal bola [1] = bola [1] - VELOCIDAD;  if (ballDirectionVerti == 'D') // mueve la bola hacia abajo en diagonal ball [1] = ball [1] + SPEED;  si (bola [1] <= 0)  // bounce the ball off the top ballDirectionVerti = 'D';  if (ball[1] >= resolución [1]) // rebotar la bola desde la parte inferior ballDirectionVerti = 'U';  if (ballDirectionHori == 'R') ball [0] = ball [0] + SPEED; // mover bola si (bola [0]> = (resolución [0] - 6)) // bola está en el borde AI de la pantalla si ((aiPos + 12)> = bola [1] && (aiPos - 12) <= ball[1])  // ball hits AI paddle if (ball[1] > (aiPos + 4)) // desviar bola hacia abajo ballDirectionVerti = 'D';  else if (bola [1] < (aiPos - 4))  // deflect ball up ballDirectionVerti = 'U';  else  // deflect ball straight ballDirectionVerti = 'S';  // change ball direction ballDirectionHori = 'L';  else  // GOAL! ball[0] = 6; // move ball to other side of screen ballDirectionVerti = 'S'; // reset ball to straight travel ball[1] = resolution[1] / 2; // move ball to middle of screen ++playerScore; // increase player score    if (ballDirectionHori == 'L')  ball[0] = ball[0] - SPEED; // move ball if (ball[0] <= 6)  // ball is at the player edge of the screen if ((playerPos + 12) >= bola [1] && (playerPos - 12) <= ball[1])  // ball hits player paddle if (ball[1] > (playerPos + 4)) // desviar bola hacia abajo ballDirectionVerti = 'D';  else if (bola [1] < (playerPos - 4))  // deflect ball up ballDirectionVerti = 'U';  else  // deflect ball straight ballDirectionVerti = 'S';  // change ball direction ballDirectionHori = 'R';  else  ball[0] = resolution[0] - 6; // move ball to other side of screen ballDirectionVerti = 'S'; // reset ball to straight travel ball[1] = resolution[1] / 2; // move ball to middle of screen ++aiScore; // increase AI score    drawBall(ball[0], ball[1]); erasePlayerPaddle(playerPos); playerPos = analogRead(A2); // read player potentiometer playerPos = map(playerPos, 0, 1023, 8, 54); // convert value from 0 - 1023 to 8 - 54 drawPlayerPaddle(playerPos); moveAi(); drawNet(); drawScore();  else  // somebody has won display.clearDisplay(); display.setTextSize(4); display.setTextColor(WHITE); display.setCursor(0, 0); // figure out who if (aiScore > playerScore) display.println ("YOU LOSE!");  else if (playerScore> aiScore) display.println ("YOU WIN!");  display.display ();  void moveAi () // mueve la paleta AI eraseAiPaddle (aiPos); if (ball [1]> aiPos) ++ aiPos;  else if (bola [1] < aiPos)  --aiPos;  drawAiPaddle(aiPos);  void drawScore()  // draw AI and player scores display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(45, 0); display.println(playerScore); display.setCursor(75, 0); display.println(aiScore);  void eraseScore()  // erase AI and player scores display.setTextSize(2); display.setTextColor(BLACK); display.setCursor(45, 0); display.println(playerScore); display.setCursor(75, 0); display.println(aiScore);  void drawNet()  for (int i = 0; i < (resolution[1] / WALL_WIDTH); ++i)  drawPixel(((resolution[0] / 2) - 1), i * (WALL_WIDTH) + (WALL_WIDTH * i), WALL_WIDTH);   void drawPixel(int posX, int posY, int dimensions)  // draw group of pixels for (int x = 0; x < dimensions; ++x)  for (int y = 0; y < dimensions; ++y)  display.drawPixel((posX + x), (posY + y), WHITE);    void erasePixel(int posX, int posY, int dimensions)  // erase group of pixels for (int x = 0; x < dimensions; ++x)  for (int y = 0; y < dimensions; ++y)  display.drawPixel((posX + x), (posY + y), BLACK);    void erasePlayerPaddle(int row)  erasePixel(0, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); erasePixel(0, row - PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(0, row, PADDLE_WIDTH); erasePixel(0, row + PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(0, row + (PADDLE_WIDTH + 2), PADDLE_WIDTH);  void drawPlayerPaddle(int row)  drawPixel(0, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); drawPixel(0, row - PADDLE_WIDTH, PADDLE_WIDTH); drawPixel(0, row, PADDLE_WIDTH); drawPixel(0, row + PADDLE_WIDTH, PADDLE_WIDTH); drawPixel(0, row + (PADDLE_WIDTH + 2), PADDLE_WIDTH);  void drawAiPaddle(int row)  int column = resolution[0] - PADDLE_WIDTH; drawPixel(column, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); drawPixel(column, row - PADDLE_WIDTH, PADDLE_WIDTH); drawPixel(column, row, PADDLE_WIDTH); drawPixel(column, row + PADDLE_WIDTH, PADDLE_WIDTH); drawPixel(column, row + (PADDLE_WIDTH * 2), PADDLE_WIDTH);  void eraseAiPaddle(int row)  int column = resolution[0] - PADDLE_WIDTH; erasePixel(column, row - (PADDLE_WIDTH * 2), PADDLE_WIDTH); erasePixel(column, row - PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(column, row, PADDLE_WIDTH); erasePixel(column, row + PADDLE_WIDTH, PADDLE_WIDTH); erasePixel(column, row + (PADDLE_WIDTH * 2), PADDLE_WIDTH);  void drawBall(int x, int y)  display.drawCircle(x, y, BALL_SIZE, WHITE);  void eraseBall(int x, int y)  display.drawCircle(x, y, BALL_SIZE, BLACK); 

Esto es lo que terminas con:

Una vez que esté seguro con el código, hay varias modificaciones que puede hacer:

  • Agrega un menú para los niveles de dificultad (cambia la IA y la velocidad de la pelota).
  • Agrega algún movimiento al azar a la pelota o IA.
  • Añadir otro bote para dos jugadores..
  • Añadir un botón de pausa.

Ahora eche un vistazo a estos proyectos de juegos retro Pi Zero 5 proyectos de juegos retro con Raspberry Pi Zero 5 proyectos de juegos retro con la Raspberry Pi Zero La Raspberry Pi Zero ha conquistado el mundo del bricolaje y el hogar, por lo que es posible revisar proyectos antiguos e inspirando a los recién llegados, especialmente en las mentes febriles de los fanáticos de los juegos retro. Lee mas .

¿Has codificado Pong usando este código? ¿Qué modificaciones hiciste? Déjame saber en los comentarios a continuación, me gustaría ver algunas fotos.!

Explorar más sobre: ​​Arduino, Electrónica, Juegos Retro..