Proiectul isi propune reinventarea jocului clasic snake prin controlarea acestuia cu un accelerometru.
Scopul proiectului este de a crea un joc distractiv si de a creea o aplicatie de dificultate medie din care sa deprind abilitatile necesare de lucru cu sistemele embedded.
Utilitatea proiectului consta in gasirea unei aplicatii practice, cunoscute si distractive pentru lucrul cu acest tip de sisteme.
Jucatorul va vedea sarpele inchis intr-un bounding box. Acesta il va putea controla, folosind accelerometrul si “impingand” sarpele intr-o anumita directie. Aceelerometrul si display-ul vor fi montate pe acelasi breadboard, astfel incat jucatorul va avea o experienta similara cu cea a unui joc pe smartphone.
Piesă | Distribuitor | Cantitate | Preț |
---|---|---|---|
PCB 2019 | ACS | 1 buc | 10 RON |
Componente de bază PM 2019 | Seria CA | 1 buc | 53 RON |
Modul ecran Nokia 5110 | Ardushop | 1 buc | 15,50 RON |
Modul giroscop + accelerometru MPU 6050 | Ardushop | 1 buc | |
Arduino UNO | Ardushop | 1 buc | 20 RON |
Fire de legatura | visteria personala | 11 buc | 0 RON |
Rezistente 1k | visteria personala | 5 buc | 0 RON |
Breadboard | visteria personala | 1 buc | 0 RON |
Total | 114 RON |
Schema de mai jos (disponibila si ca .sch) pt download, reprezinta schema de design a proiectului.
Display-ul este legat prin mai multe rezistente pentru a prelungi speranta de viata a acestuia.
Unele dintre conexiuni sunt realizate prin bus-uri, in ideea in care proiectul poate fi extins pentru a include mai multe periferice, spre exemplu difuzoare pentru muzica sau un joystick pentru input ce ar putea fi selectat prin CS.
De asemenea, schema a fost completata si cu o parte din componentele de pe PCB-ul PM2019 (capacitors & quartz crystal) in vederea respectarii limitarilor ERC.
Pentru realizarea proiectului am folosit mai multe resurse software:
Am folosit atat biblioteci standard (stdio/stdlib), cat si biblioteci avr. De asemenea, a fost nevoie sa folosesc biblioteci 3rd party de pe github pentru o mai buna interactionare cu periferice (display nokia si mpu6050).
#include <stdio.h> #include <stdlib.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <util/delay.h> #include <string.h> #include "nokia5110/nokia5110.h" #include "mpu6050/mpu6050.h"
In afara de initializari, jocul se petrece intr-o bucla infinita.
La inceput, initializez miscarea si pozitia sarpelui. Datorita limitarilor de spatiu, sarpele are o dimensiune maxima de 100 de patratele. Peste 100 de puncte jocul poate continua, insa, desi acumuleaza puncte, sarpele jucatorului nu mai creste.
// hold snake in int * int * snake = calloc(100, sizeof(int)); snake[0] = 23 * 81 + 41; // init snake snake[1] = 23 * 81 + 42; snake[2] = 23 * 81 + 43; snake[3] = 23 * 81 + 44; // hold moving array to account for snake movement char *moving = calloc(100, sizeof(char)); moving[0] = RIGHT; // set init direction as right moving[1] = RIGHT; moving[2] = RIGHT; moving[3] = RIGHT;
In joc, avem 4 pereti, ce sunt afisati printr-o functie render_walls(). Pe langa acestia, avem sarpele si bonusul ce trebuie colectat.
Sarpele se misca o data per iteratie, iar pentru acest lucru folosim array-ul “move”.
// adjust movement for (i = 0; i < CRT_SNAKE_SIZE - 1; i++) { moving[i] = moving[i + 1]; } moving[CRT_SNAKE_SIZE - 1] = getInputUpdate(moving[CRT_SNAKE_SIZE - 1]);
Directia de miscare se seteaza in capul sarpelui, iar, ca o unda, miscarea se propaga cu 1 pozitie la stanga in array, pentru a imita miscarea din jocul clasic.
Inputul, cum se vede in sectiunea de cod de mai sus, este luat de la modulul accelerometru + giroscop prin metoda getInputUpdate.
Daca senzorul este miscat peste un anumit threshold pe o directie, se ofera un update. In caz contrar, la miscari mici, sarpele isi pastreaza directia de deplasare. Astfel, se evita inputuri accidentale.
char getInputUpdate(char same) { double axg = 0; double ayg = 0; double azg = 0; double gxds = 0; double gyds = 0; double gzds = 0; mpu6050_getConvData(&axg, &ayg, &azg, &gxds, &gyds, &gzds); // check tilt backward if (axg > LIMIT) { return DOWN; } // check tilt forward if (axg < -LIMIT) { return UP; } // check tilt left if (ayg < -LIMIT) { return LEFT; } // check tilt right if (ayg > LIMIT) { return RIGHT; } return same; }
Detectia coliziunilor se realizeaza prin doua metode, una de verificare a coliziunilor cu peretii (verificam daca sarpele atinge limitele superioare/inferioare ale arenei) si una de verificare de coliziuni cu sine (iterare prin array-ul sarpelui pentru a vedea daca exista doua valori egale).
// check if snake eats itself by double iteration int getSelfColision(int *snake, int snakeSize) { int i, j; for (i = 0; i < snakeSize - 1; i++) { for (j = i + 1; j < snakeSize; j++) { if (snake[i] == snake[j]) { return 1; } } } return 0; } // check snake coliding with walls (out of bounding box fail) int getWallsColision(int *snake, int snakeSize) { int i, x, y; for (i = 0; i < snakeSize; i++) { x = snake[i] % 81 + 1; y = snake[i] / 81 + 1; if (x == 0 || x == 81 || y == 0 || y == 42) { return 1; } } return 0; }
Exista si o a treia meotda de detectare a coliziunilor ce verifica daca sarpele va lua un bonus, plus o metoda ce detecteaza daca un bonus este pe suprafata sarpelui, pentru a evita cazul in care bonusul se spown-eaza peste sarpe.
Snake este un joc clasic de tip arcade, dezvoltat pentru prima data in 1976. Realizarea acestuia pe atmega324pa reprezinta un challenge, data fiind limitarea de memorie si nivelul low-level al codului.
Controlul clasic pentru un astfel de joc este realizat prin butone sau joystick, insa pentru a avea o nota de originalitate, proiectul de fata isi propune realizarea inputului printr-un modul accelerometru & giroscop.
La initializarea jocului, sarpele are un corp format din 4 patratele si se deplaseaza catre dreapta.
Scena jocului este inconjurata de 4 pereti. Daca sarpele se loveste de pereti sau de sine, jocul este reinitializat, iar pe ecran este afisat scorul jucatorului.
Scopul jocului este de a acumula cat mai multe puncte prin “inghitirea” (atingerea) pixelilor-bonus. Inghitirea fiecarui punct duce la incrementarea sarpelui.
Pentru a schimba directia de deplasare a saprelui, se inclina modului BreadBoard-display-accelerometru/giroscop in fata (UP), in sapte (DOWN), la stanga (LEFT) la dreapta (RIGHT).
Atentie insa, inclinarea catre stanga cand sarpele se deplaseaza la dreapta, sau orice miscare similara este valida si va duce, evident, la o intoarcere de 180 de grade. Astfel, sarpele se va “manca” singur si va fi game over.
Snake a fost unul dintre primele jocuri pe care l-am jucat vreoadata, pe un vechi telefon Nokia. Sa implementez acest joc de la zero, inclusiv lipit rezistente pe PCB a fost o experienta unica, foarte placuta, probabil unul dintre lucrurile pe care mi le voi aminti cu placere din facultate.
Desigur, sunt multe lucruri care pot fi inbunatatite - eliminarea breadboard-ului, lipituri mai bune, software mai modularizat, adaugare de extra functionalitati, insa sunt multumit de rezultatul obtinut.