Tabla de contenido:

Arduino OLED Snake Game: 3 pasos
Arduino OLED Snake Game: 3 pasos

Video: Arduino OLED Snake Game: 3 pasos

Video: Arduino OLED Snake Game: 3 pasos
Video: Classic Snake Game On 8x8 LED Matrix With Chat-GPT Generated Arduino Code | Coders Cafe 2024, Mes de julio
Anonim
Juego Arduino OLED Snake
Juego Arduino OLED Snake

Hola y bienvenido, a nuestras instrucciones sobre cómo hacer un juego OLED arduino, este proyecto surgió cuando intentábamos hacer nuestro primer juego con un arduino, así que pensamos dónde era mejor comenzar que el clásico Snake de Nokia (bueno en al menos un clon de serpiente:)).

Que necesitarás

Suministros

Arduino UNO o clon

Pantalla OLED

4 diodos

Resistencia de 500-1k

4 botones del controlador

Zumbador piezoeléctrico pasivo

Opcional

BreadBoard sin soldadura

Tenga en cuenta que estos enlaces son solo por ejemplo

Paso 1: el circuito

El circuito
El circuito

En la imagen de arriba puede ver nuestro circuito, usamos el pin d3 en el arduino como un pin de solicitud de interrupción para que el arduino dé prioridad a la lectura de las entradas del controlador que son d4 d5 d6 d7. Lo básico del circuito es que se presiona un botón de dirección que sube a 5v, esto activa el pin de solicitud de interrupción (cable púrpura d3) y un pin de dirección correspondiente, la función de interrupción llama a una función de dirección de actualización y ese código mueve la serpiente en consecuencia. El pin 9 se utiliza como pin de sonido, ya que es un PWM (~ modulación de ancho de pulso) que está conectado directamente a un piezoeléctrico de 5v en el pin + y el - vuelve a 0v / tierra.

(Para su información, en el arduino uno y los clones solo d2 y d3 pueden actuar como pines de solicitud de interrupción).

Pines de dirección:

d4 Up NARANJA

d5 Abajo ROSA

d6 Izquierda AZUL

d7 Derecha MARRÓN

d9 sonido GRIS

Cada botón tiene una entrada de conexión de 5v y una salida que se conecta primero a su respectiva entrada digital en el arduino, esta misma salida de cada botón se conecta luego a su propio diodo, usamos los diodos para detener la retroalimentación de voltaje a través del otros botones y activándolos. En el extremo del cátodo (-) de los 4 diodos los unimos para crear una unión de salida que se conecta a d3 y luego a través de una resistencia a 0v / tierra para tirar de los pines arduino hacia abajo para no dejar pines flotantes cuando no esté activado.

(Para su información, un pin flotante puede recibir voltaje fantasma y causar un comportamiento inusual)

Se utilizan 2 pines analógicos para controlar la pantalla, estos son los pines i2c del hardware arduino.

A5 está conectado a SCL AMARILLO

A4 está conectado a SDA GREEN

La salida de + 5v y 0v (tierra) del arduino se utiliza como fuente de energía para todo el circuito, que puede ser alimentado por un cargador USB o de teléfono.

Paso 2: el código

// ------------------------ ANJAWARE SNAKE Games Con la ayuda de la gente de la red --------------- -------

#incluir

#include // https://github.com/adafruit/Adafruit-GFX-Library #include // https://github.com/adafruit/Adafruit-GFX-Library // conjunto de visualización (ancho, alto) Adafruit_SSD1306 display (128, 64); // definir pines de entrada estos son los pines en el arduino que nunca cambian así que #define #define INTPIN 3 // solo los pines 2 y 3 pueden ser pines interrumpidos en UNO #define UPPIN 4 // estos son pines conectados al interruptor relevante #define DWNPIN 5 #define LFTPIN 6 #define RHTPIN 7 #define SND 9 // define direcciones #define DIRUP 1 // estos valores es lo que la "serpiente" mira para decidir- #define DIRDOWN 2 // la dirección en que viajará la serpiente # definir DIRLEFT 3 #definir DIRRIGHT 4

// establecer variables de botón

// volitile porque necesitamos que se actualice con el interupt, por lo que puede ser cualquier bit del valor del ciclo

// nunca es superior a 4, por lo que solo se necesita un int de 8 bits para ahorrar recursos volátiles uint8_t buttonpressed = 0; bool butup = 0; bool butdown = 0; // usamos esto para establecer true para "detectar" en qué dirección presionó bool butleft = 0; bool butright = 0;

// entradas de serpiente

byte snakePosX [30]; // matriz para hacer el cuerpo del byte serpiente snakePosY [30];

int snakeX = 30; // posición de la cabeza de la serpiente

int snakeY = 30; int tamaño de la serpiente = 1; // recuento del tamaño de la serpiente limitado al tamaño de la matriz

// ints del mundo

uint8_t worldMinX = 0; // estos establecen los límites del área de juego

uint8_t worldMaxX = 128; uint8_t worldMinY = 10; uint8_t worldMaxY = 63;

// recolecta scran (comida) y posición de scran

bool scranAte = 0; uint8_t scranPosX = 0; uint8_t scranPosY = 0;

// puntúa variables

Playcore largo = 0; puntuación alta larga = 30; // establecer la puntuación alta en 3 recopilar como punto de partida

// --------------------------- esto es lo que ejecuta la interrupción en caso de aumento de voltaje ------------ -------------

vacío interrumpido presionado () {retraso (150); // ligero retraso para la protección adicional de "rebote" updatedirection (); } // ------------------ actualiza el valor de la dirección presionando el botón ----------------- void updatedirection () { // Serial.println ("dirección de actualización"); butup = digitalRead (UPPIN); // comprobar qué entrada fue alta y establecer bool true relevante butdown = digitalRead (DWNPIN); butleft = digitalRead (LFTPIN); butright = digitalRead (RHTPIN); // estos si los enunciados miran qué entrada fue alta e ingresa el valor relevante en "botón presionado" // variable, esta variable dicta la dirección del movimiento if (butup == true) {buttonpressed = DIRUP; // Serial.println ("UP presionado"); // Serial.println (botón presionado); butup = falso; tono (SND, 1500, 10); } if (butdown == true) {buttonpressed = DIRDOWN; // Serial.println ("ABAJO presionado"); // Serial.println (botón presionado); butdown = falso; tono (SND, 1500, 10); }

si (butleft == verdadero)

{botón presionado = DIRLEFT; // Serial.println ("IZQUIERDA presionada"); // Serial.println (botón presionado); butleft = falso; tono (SND, 1500, 10); } if (butright == true) {buttonpressed = DIRRIGHT; // Serial.println ("DERECHO presionado"); // Serial.println (botón presionado); butright = falso; tono (SND, 1500, 10); }}

// -------------------------- dibuja las rutinas de visualización ------------------ -----------------

void updateDisplay () // dibuja puntuaciones y contornos

{// Serial.println ("Actualizar pantalla");

display.fillRect (0, 0, display.width () - 1, 8, NEGRO);

display.setTextSize (0); display.setTextColor (BLANCO); // dibujar puntuaciones display.setCursor (2, 1); display.print ("Puntuación:"); display.print (String (playcore, DEC)); display.setCursor (66, 1); display.print ("Alto:"); display.print (String (puntuación más alta, DEC)); // dibujar área de juego // pos 1x, 1y, 2x, 2y, color display.drawLine (0, 0, 127, 0, WHITE); // borde superior display.drawLine (63, 0, 63, 9, BLANCO); // separador de puntuación display.drawLine (0, 9, 127, 9, BLANCO); // debajo del borde del texto display.drawLine (0, 63, 127, 63, BLANCO); // borde inferior display.drawLine (0, 0, 0, 63, BLANCO); // borde izquierdo display.drawLine (127, 0, 127, 63, BLANCO); // borde derecho

}

// ----------------------------------- actualizar el área de juego ---------- --------------------

void updateGame () // esto actualiza la pantalla del área de juego

{display.clearDisplay ();

display.drawPixel (scranPosX, scranPosY, BLANCO);

scranAte = scranFood ();

// comprobar las rutinas de las serpientes

if (outOfArea () || selfCollision ())

{ juego terminado(); }

// mostrar serpiente

para (int i = 0; i0; i--) {snakePosX = snakePosX [i-1]; snakePosY = snakePosY [i-1]; } // agrega un píxel extra a la serpiente if (scranAte) {snakeSize + = 1; snakePosX [snakeSize-1] = snakeX; snakePosY [serpienteSize-1] = snakeY; }

switch (botón presionado) // era snakeDirection

{caso DIRUP: serpienteY- = 1; rotura; caso DIRDOWN: snakeY + = 1; rotura; caso DIRLEFT: snakeX- = 1; rotura; caso DIRRIGHT: snakeX + = 1; rotura; } snakePosX [0] = snakeX; snakePosY [0] = snakeY; updateDisplay (); display.display (); // --------------------- coloca el scran -------------------

vacío placeScran ()

{scranPosX = aleatorio (worldMinX + 1, worldMaxX-1); scranPosY = aleatorio (worldMinY + 1, worldMaxY-1); } // ------------------------ SCRAN ATE PUNTO HACIA ARRIBA ---------------- bool scranFood () {if (snakeX == scranPosX && snakeY == scranPosY) {playcore = playcore + 10; tono (SND, 2000, 10); updateDisplay (); placeScran (); return 1; } else {return 0; } } //--------------------- fuera del área---------------------- bool outOfArea () {return snakeX = worldMaxX || snakeY = worldMaxY; } //---------------------- juego terminado----------------------- --- void gameOver () {uint8_t rectX1, rectY1, rectX2, rectY2; rectX1 = 38; rectY1 = 28; rectX2 = 58; rectY2 = 12; display.clearDisplay (); display.setCursor (40, 30); display.setTextSize (1); tono (SND, 2000, 50); display.print ("JUEGO"); tono (SND, 1000, 50); display.print ("OVER"); if (playcore> = highscore) // compruebe si la puntuación es más alta que la puntuación alta {highscore = playcore; // declaración única para actualizar la puntuación alta} for (int i = 0; i <= 16; i ++) // esto es para dibujar rectanlges alrededor del juego sobre {display.drawRect (rectX1, rectY1, rectX2, rectY2, WHITE); Serial.println ("si bucle"); display.display (); rectX1- = 2; // desplazarse 2 píxeles rectY1- = 2; rectX2 + = 4; // desplazar 2 píxeles desde el último punto rectY2 + = 4; tono (SND, i * 200, 3); } display.display (); // Limpiar pantalla después de la fama sobre rectX1 = 0; // establecer la posición inicial de la línea rectY1 = 0; rectX2 = 0; rectY2 = 63; para (int i = 0; i <= 127; i ++) {uint8_t cnt = 0; display.drawLine (rectX1, rectY1, rectX2, rectY2, NEGRO); rectX1 ++; rectX2 ++; display.display (); } display.clearDisplay (); Playcore = 0; // restablecer los detalles de la serpiente y el jugador snakeSize = 1; snakeX = display.width () / 2; serpienteY = display.height () / 2; waitForPress (); // esperar a que el jugador inicie el juego} // ------------------------- esperar el bucle de pulsaciones ---------- --------------- void waitForPress () {bool esperando = 0; // El ciclo termina cuando esto es cierto display.clearDisplay (); while (esperando == 0) {drawALineForMe (BLANCO); // dibuja una línea blanca aleatoria drawALineForMe (BLACK); // dibuja una línea negra aleatoria para que la pantalla no se llene completamente en blanco display.fillRect (19, 20, 90, 32, BLACK); // fondo en blanco para el texto display.setTextColor (WHITE); display.setCursor (35, 25); display.setTextSize (2); // display de fuente más grande.println ("SERPIENTE"); // x y w h r col display.drawRoundRect (33, 22, 62, 20, 4, BLANCO); // Serpiente de borde display.drawRect (19, 20, 90, 32, BLANCO); // cuadro de borde - 3 display.setCursor (28, 42); display.setTextSize (0); // la fuente vuelve a la pantalla normal.println ("presione cualquier tecla"); display.display (); esperando = digitalRead (INTPIN); // verifica si la tecla presionada esperando cambiará a 1 terminando mientras el botón presionado = 0; // presionar el botón de reinicio}} // -------------------- DIBUJAR un color de entrada de línea aleatorio uint8_t -------------- ----- vacío drawALineForMe (uint8_t clr) {uint8_t línea1X, línea1Y, línea2X, línea2Y = 0; // establecer coordenadas aleatorias para una línea y luego dibujarla // variable no menos no más line1X = random (worldMinX + 1, worldMaxX-1); line1Y = aleatorio (worldMinY + 1, worldMaxY-1); line2X = aleatorio (worldMinX + 1, worldMaxX-1); line2Y = aleatorio (worldMinY + 1, worldMaxY-1); display.drawLine (línea1X, línea1Y, línea2X, línea2Y, clr); } // ------------------------------------- detección de colisiones -------- -----------------------

for (byte i = 4; i <tamaño serpiente; i ++) {if (serpienteX == serpientePosX && serpienteY == serpientePosy ) {return 1; tono (SND, 2000, 20); tono (SND, 1000, 20); } return 0; }

//-------------------------------- CONFIGURACIÓN--------------- -------------------------------

configuración vacía () {retraso (100); // simplemente dale a las cosas la oportunidad de "arrancar" // Serial.begin (9600); // desmarque esto si desea ver las salidas en serie display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay (); // comenzar con una pantalla limpia display.setTextColor (WHITE); // configurar el tamaño de rotación del color del texto, etc. display.setRotation (0); display.setTextWrap (falso); display.dim (0); // establece el brillo de la pantalla pinMode (INTPIN, INPUT); // establece los puertos correctos para las entradas pinMode (UPPIN, INPUT); pinMode (DWNPIN, ENTRADA); pinMode (LFTPIN, ENTRADA); pinMode (RHTPIN, ENTRADA); // este es el comando interupt esto "detiene" el arduino para leer las entradas // comando-función-pin-función para ejecutar-condición en el pin attachInterrupt (digitalPinToInterrupt (INTPIN), interruptpressed, RISING); // Serial.println ("Configuración aprobada"); waitForPress (); // muestra la pantalla de inicio de la serpiente placeScran (); // coloca el primer trozo de comida} // --------------------- BUCLE PRINCIPAL ----------------- ---------------------- vacío loop () {updateGame (); // esta función es la que lleva el código principal}

Paso 3:

Recomendado: