Índice:

Jogo Arduino OLED Snake: 3 etapas
Jogo Arduino OLED Snake: 3 etapas

Vídeo: Jogo Arduino OLED Snake: 3 etapas

Vídeo: Jogo Arduino OLED Snake: 3 etapas
Vídeo: How to play SNAKE on an Arduino 2024, Julho
Anonim
Jogo Arduino OLED Snake
Jogo Arduino OLED Snake

Olá e bem-vindo, às nossas instruções sobre como fazer um jogo OLED arduino, este projeto surgiu quando estávamos tentando fazer nosso primeiro jogo com um arduino, muuuuito, pensamos em onde melhor começar do que o clássico do nokia Snake (bem em pelo menos um clone de cobra:)).

O que você vai precisar

Suprimentos

Arduino UNO ou clone

Display OLED

4 diodos

Resistor 500-1k

4 botões de controle

Campainha Piezo passiva

opcional

Pão sem solda

Observe que esses links são apenas para exemplo

Etapa 1: O circuito

O circuito
O circuito

Na imagem acima você pode ver nosso circuito, usamos o pino d3 no arduino como um pino de solicitação de interrupção para que o arduino dê prioridade à leitura das entradas do controlador que são d4 d5 d6 d7. O básico do circuito é que um botão de direção é pressionado que vai alto 5v, isso ativa o pino de solicitação de interrupção (fio roxo d3) e um pino de direção correspondente, a função de interrupção chama uma função de atualização de direção e esse código move a cobra de acordo. O pino 9 é usado como o pino de som, pois é um PWM (modulação de largura de pulso ~) que é conectado diretamente a um piezo de 5v no pino + e - volta para 0v / terra.

(Para sua informação no arduino uno e clones apenas d2 e d3 podem atuar como pinos de solicitação de interrupção).

Alfinetes de direção:

d4 Up LARANJA

d5 Down PINK

d6 Esquerdo AZUL

d7 MARROM DIREITO

d9 som CINZA

Cada botão tem uma entrada de conexão em 5v e uma saída que é conectada primeiro à sua respectiva entrada digital no Arduino, esta mesma saída de cada botão é então conectada ao seu próprio diodo, usamos os diodos para parar a alimentação de tensão de volta para o outros botões e ativando-os. Na extremidade do cátodo (-) de todos os 4 diodos, nós os juntamos para criar uma junção de saída que se conecta a d3 e, em seguida, através de um resistor a 0v / terra para puxar os pinos do arduino para baixo de modo a não deixar os pinos flutuantes quando não estiverem ativado.

(Para sua informação, um pino flutuante pode receber tensão fantasma e causar um comportamento incomum)

2 pinos analógicos são usados para conduzir a tela, estes são os pinos i2c do hardware do Arduino.

A5 está conectado a SCL AMARELO

A4 está conectado a SDA GREEN

A saída de + 5v e 0v (terra) do arduino é usada como fonte de energia para todo o circuito, que pode ser alimentado por USB ou carregador de telefone.

Etapa 2: O Código

// ------------------------ Jogos ANJAWARE SNAKE Com a ajuda dos povos da Internet --------------- -------

#incluir

#include // https://github.com/adafruit/Adafruit-GFX-Library #include // https://github.com/adafruit/Adafruit-GFX-Library // conjunto de exibição (largura, altura) exibição Adafruit_SSD1306 (128, 64); // define os pinos de entrada, esses são os pinos no arduino, eles nunca mudam, então #define #define INTPIN 3 // apenas os pinos 2 e 3 podem ser pinos de interrupção em UNO #define UPPIN 4 // esses são pinos conectados ao switch relevante #define DWNPIN 5 #define LFTPIN 6 #define RHTPIN 7 #define SND 9 // define direções #define DIRUP 1 // esses valores é o que a "cobra" olha para decidir- #define DIRDOWN 2 // a direção em que a cobra vai viajar # definir DIRLEFT 3 #define DIRRIGHT 4

// definir variáveis de botão

// volitile porque precisamos atualizar com a interrupção, então pode ser qualquer bit de valor de ciclo

// nunca é maior que 4, portanto, só precisa de 8 bits int para economizar recursos volatile uint8_t buttonpressed = 0; bool butup = 0; bool butdown = 0; // usamos isso para definir true para "detectar" em qual direção pressionado bool butleft = 0; bool butright = 0;

// snake ints

byte snakePosX [30]; // array para criar o corpo do byte snake snakePosY [30];

int snakeX = 30; // posição da cabeça da cobra

int snakeY = 30; int snakeSize = 1; // contagem do tamanho da cobra limitada ao tamanho da matriz

// world ints

uint8_t worldMinX = 0; // estes definem os limites da área de jogo

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

// coleta o scran (alimento) e a posição do scran

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

// pontua variáveis

pontuação longa = 0; recorde longo = 30; // defina a pontuação mais alta para 3 coletar como ponto de partida

// --------------------------- isto é o que a interrupção executa no aumento de tensão ------------ -------------

vazio interrompido () {atraso (150); // pequeno atraso para proteção de "salto" adicionada updatedirection (); } // ------------------ atualiza o valor de direção ao pressionar o botão ----------------- void updatedirection () { // Serial.println ("updatesdirection"); butup = digitalRead (UPPIN); // verificar qual entrada foi alta e definir relevante bool true butdown = digitalRead (DWNPIN); butleft = digitalRead (LFTPIN); butright = digitalRead (RHTPIN); // estes if statemeents olham para qual input foi alto e insere o valor relevante na variável "buttonpressed" //, esta variável dita a direção do movimento if (butup == true) {buttonpressed = DIRUP; // Serial.println ("UP pressionado"); // Serial.println (buttonpressed); butup = falso; tom (SND, 1500, 10); } if (butdown == true) {buttonpressed = DIRDOWN; // Serial.println ("pressionado para BAIXO"); // Serial.println (buttonpressed); butdown = false; tom (SND, 1500, 10); }

if (butleft == true)

{buttonpressed = DIRLEFT; // Serial.println ("LEFT pressionado"); // Serial.println (buttonpressed); butleft = false; tom (SND, 1500, 10); } if (butright == true) {buttonpressed = DIRRIGHT; // Serial.println ("RIGHT pressionado"); // Serial.println (buttonpressed); butright = false; tom (SND, 1500, 10); }}

// -------------------------- desenha as rotinas de exibição ------------------ -----------------

void updateDisplay () // desenha pontuações e contornos

{// Serial.println ("Atualizar exibição");

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

display.setTextSize (0); display.setTextColor (WHITE); // desenha as pontuações display.setCursor (2, 1); display.print ("Pontuação:"); display.print (String (playcore, DEC)); display.setCursor (66, 1); display.print ("Alto:"); display.print (String (highscore, DEC)); // desenha a área de jogo // pos 1x, 1y, 2x, 2y, color display.drawLine (0, 0, 127, 0, WHITE); // borda superior display.drawLine (63, 0, 63, 9, WHITE); // separador de pontuação display.drawLine (0, 9, 127, 9, WHITE); // abaixo da borda do texto display.drawLine (0, 63, 127, 63, WHITE); // borda inferior display.drawLine (0, 0, 0, 63, WHITE); // borda esquerda display.drawLine (127, 0, 127, 63, WHITE); // borda direita

}

// ----------------------------------- atualizar área de jogo ---------- --------------------

void updateGame () // atualiza a exibição da área de jogo

{display.clearDisplay ();

display.drawPixel (scranPosX, scranPosY, WHITE);

scranAte = scranFood ();

// verificar as rotinas da cobra

if (outOfArea () || selfCollision ())

{ fim de jogo(); }

// exibir cobra

para (int i = 0; i0; i--) {snakePosX = snakePosX [i-1]; snakePosY = snakePosY [i-1]; } // adiciona um pixel extra à cobra if (scranAte) {snakeSize + = 1; snakePosX [snakeSize-1] = snakeX; snakePosY [snakeSize-1] = snakeY; }

switch (buttonpressed) // era snakeDirection

{caso DIRUP: cobraY- = 1; pausa; caso DIRDOWN: snakeY + = 1; pausa; caso DIRLEFT: snakeX- = 1; pausa; caso DIRRIGHT: snakeX + = 1; pausa; } snakePosX [0] = snakeX; snakePosY [0] = snakeY; updateDisplay (); display.display (); // --------------------- coloque o scran -------------------

void placeScran ()

{scranPosX = aleatório (worldMinX + 1, worldMaxX-1); scranPosY = aleatório (worldMinY + 1, worldMaxY-1); } // ------------------------ SCRAN ATE POINT UP ---------------- bool scranFood () {if (snakeX == scranPosX && snakeY == scranPosY) {playcore = playscore + 10; tom (SND, 2000, 10); updateDisplay (); placeScran (); return 1; } else {return 0; } } //--------------------- fora da área---------------------- bool outOfArea () {return snakeX = worldMaxX || snakeY = worldMaxY; } //---------------------- fim de jogo----------------------- --- 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); tom (SND, 2000, 50); display.print ("GAME"); tom (SND, 1000, 50); display.print ("OVER"); if (playscore> = playscore) // verifique se a pontuação é maior que a pontuação alta {highscore = playscore; // única instrução if para atualizar a pontuação mais alta} para (int i = 0; i <= 16; i ++) // isso é para desenhar retângulos em torno do jogo em {display.drawRect (rectX1, rectY1, rectX2, rectY2, WHITE); Serial.println ("se loop"); display.display (); rectX1- = 2; // desloca em 2 pixels rectY1- = 2; rectX2 + = 4; // desloca mais de 2 pixels do último ponto rectY2 + = 4; tom (SND, i * 200, 3); } display.display (); // Tela Wipe após fama sobre rectX1 = 0; // define a posição inicial da linha rectY1 = 0; rectX2 = 0; rectY2 = 63; para (int i = 0; i <= 127; i ++) {uint8_t cnt = 0; display.drawLine (rectX1, rectY1, rectX2, rectY2, BLACK); rectX1 ++; rectX2 ++; display.display (); } display.clearDisplay (); playcore = 0; // redefine os detalhes da cobra e do jogador snakeSize = 1; snakeX = display.width () / 2; cobraY = display.height () / 2; waitForPress (); // aguarde o jogador iniciar o jogo} // ------------------------- aguarde o loop de pressionamentos ---------- --------------- vazio waitForPress () {bool esperando = 0; // o loop termina quando isso é verdadeiro display.clearDisplay (); enquanto (esperando == 0) {drawALineForMe (WHITE); // desenha uma linha branca aleatória drawALineForMe (BLACK); // desenha uma linha preta aleatória para que a tela não preencha completamente o branco display.fillRect (19, 20, 90, 32, BLACK); // fundo em branco para texto display.setTextColor (WHITE); display.setCursor (35, 25); display.setTextSize (2); // fonte maior display.println ("SNAKE"); // x y w h r col display.drawRoundRect (33, 22, 62, 20, 4, WHITE); // border Snake display.drawRect (19, 20, 90, 32, WHITE); // caixa de borda - 3 display.setCursor (28, 42); display.setTextSize (0); // fonte de volta ao normal display.println ("pressione qualquer tecla"); display.display (); esperando = digitalRead (INTPIN); // verifique se a tecla em espera pressionada mudará para 1 terminando enquanto buttonpressed = 0; // botão de reset pressionado}} // -------------------- DESENHE uma cor de entrada de linha aleatória uint8_t -------------- ----- vazio drawALineForMe (uint8_t clr) {uint8_t linha1X, linha1Y, linha2X, linha2Y = 0; // definir coordenadas aleatórias para uma linha e então desenhá-la // variável nem menos nem mais line1X = random (worldMinX + 1, worldMaxX-1); linha1Y = aleatório (worldMinY + 1, worldMaxY-1); line2X = aleatório (worldMinX + 1, worldMaxX-1); linha2Y = aleatório (worldMinY + 1, worldMaxY-1); display.drawLine (linha1X, linha1Y, linha2X, linha2Y, clr); } // ------------------------------------- detecção de colisão -------- -----------------------

for (byte i = 4; i <snakeSize; i ++) {if (snakeX == snakePosX && snakeY == snakePosy ) {return 1; tom (SND, 2000, 20); tom (SND, 1000, 20); } return 0; }

//-------------------------------- CONFIGURAR--------------- -------------------------------

configuração vazia () {atraso (100); // apenas dê ao material uma chance de "inicializar" // Serial.begin (9600); // desmarque se quiser ver as saídas seriais display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay (); // começa com uma exibição limpa display.setTextColor (WHITE); // configura o tamanho da rotação da cor do texto etc display.setRotation (0); display.setTextWrap (false); display.dim (0); // define o brilho do display pinMode (INTPIN, INPUT); // define as portas corretas para entradas pinMode (UPPIN, INPUT); pinMode (DWNPIN, INPUT); pinMode (LFTPIN, INPUT); pinMode (RHTPIN, INPUT); // este é o comando de interrupção que "pára" o arduino para ler as entradas // comando-função-pino-função para executar a condição no pino attachInterrupt (digitalPinToInterrupt (INTPIN), interrompido, RISING); // Serial.println ("Configuração aprovada"); waitForPress (); // exibe a tela de inicialização do snake placeScran (); // coloque o primeiro pedaço de comida} // --------------------- MAIN LOOP ----------------- ---------------------- void loop () {updateGame (); // esta função é o que carrega o código principal}

Etapa 3:

Recomendado: