Proiectul are ca scop implementarea unui joc arcade de tip Breakout derivat din jocul clasic Pong utilizand un display de Nokia 3310.
Este un tip de joc destul de raspandit fiind usor de inteles si utilizat. Variatii ale acestuia se pot intalni atat pe telefoane cat si online.
In parte de sus a ecranului se afla un numar de “caramizi”, blocuri ce sunt distruse cu ajutorul unei bile. Bila traverseaza ecranul si ricoseaza din peretii laterali si din peretele superior. Jocul se incheie cu succes in momentul in care toate blocurile sunt distruse. Daca bila atinge peretele inferior al ecranului, jocul este pierdut. Pentru a evita acest lucru jucatorul controleaza un pad situat in partea de jos a ecranului pe care il poate deplasa doar la stanga sau la dreapta. La contactul cu pad-ul bila ricoseaza.
Implementarea hardware utilizeaza placa de baza realizata la etapa I a proiectului. Placa de baza contine un microcontroller ATmega16.
Pentru afisaj se utilizeaza un display de Nokia3310.
Seminificatie pini conform datasheet-ului (vezi resurse [2]):
Se observa ca LCD-ul de Nokia necesita 3.3V dar voltajul generat de ATmega16 este de 5V. Astfel s-a recurs la utilizarea unor divizoare de tensiune pentru fiecare dintre cei 6 pini conectati la microcontroller.
U2 = U1 * R2 / (R1 + R2), unde U2 = 3.3V necesari pentru LCD si U1 = 5V de la ATmega16.
⇒ 3.3*R1 = 1.7*R2 ⇒ (evident) R1 = 1.7K si R2 = 3.3K dar cum nu am gasit decat de 1.8K sau 1.6K am ales rezistente de 1.8K.
Conectare LCD Nokia 3310:
LCD | ATMEGA16 |
---|---|
1 (VDD) | VCC |
2 (SCLK) | PB7 |
3 (SDIN) | PB5 |
4 (D/C) | PB0 |
5 (SCE) | PB4 |
6 (GND) | |
7 (VOUT) | |
8 (RES) | PB6 |
Controlul asupra pad-ului se realizeaza prin intermediul a doua butoane.
Conform celor precizate mai sus si datasheet-ului pentru ATmega16 (vezi resurse [3]) schema de conectare a componentelor precizate cu microcontrollerul este urmatoarea:
Programarea microcontroller-ului este realizata integral in C.
Pentru comunicarea cu Nokia3310 am utilizat driver-ul de pe Quantum Torque cu urmatoarele functii (pe care le-am folosit eu) deja implementate:
De asemenea driverul suporta apelul printf pentru afisarea pe ecran utilizand functiile lcd_chr (afisare caracter) si lcd_str (afisare string).
Pentru testarea in Proteus a fost necesara instalarea separata a librariei pentru display. Am utilizat urmatoarea schema:
Pentru compatibilitatea cu schema proprie am configurat pinii pentru LCD in header-ul driver-ului astfel:
#define LCD_CLK_PIN (1<<PB7) #define LCD_DATA_PIN (1<<PB5) #define LCD_DC_PIN (1<<PB0) #define LCD_CE_PIN (1<<PB4) #define LCD_RST_PIN (1<<PB6) #define LCD_PORT PORTB #define LCD_DDR DDRB
Verificare coliziune bila-bloc
Testul de verificare a coliziunii se apeleaza din functia de desenare a bilei doar atunci cand aceasta se afla in zona blocurilor.
void collision_detection (void) { int i; for (i = xgl_ball; i < (xgl_ball + 3); i++) if (ball[x_ball][i-xgl_ball] & blocks[y_ball-1][i-1]) { //avem coliziune nr_blocks --; points += 100; if (nr_blocks == 0) //nu mai sunt blocuri in joc gameState = 2; //identificare bloc coliziune //pozitiile relative a blocurilor in cadrul liniei se cunosc if ((i-1) < 17) { //se sterge blocul de pe ecran si din memorie (varibila) remove_block (7, y_ball); return; } if ((i-1) < 38) { remove_block (28, y_ball); return; } if ((i-1) < 59) { remove_block (49, y_ball); return; } if ((i-1) < 80) { remove_block (70, y_ball); return; } return; } }
Verificare Game Over
Functia de mai jos este apelata de functia de desenare a bilei cand aceasta se afla pe ultima linie pentru a verifica daca atinge pad-ul sau nu.
void check_end_game(void) { //ca sa nu fie end game tb sa fie diferit de 0 unsigned char res = 0; for (int i = xgl_ball; i < (xgl_ball + 3); i++) //verifica daca bila atinge pad-ul res |= (ball[x_ball][i - xgl_ball] & pad_line[i]); if (res == 0) { //bila nu a atins pad-ul gameState = 2; //se incheie jocul gameOver = 1; //jucatorul a pierdut } else { //verificare schimbare directie if (xgl_ball >= (x_pad + 4) && xgl_ball <= (x_pad + 6)) x_ball_dir = 0; //perpendicular else if (xgl_ball < (x_pad + 4)) x_ball_dir = -1; //diagonal stanga else x_ball_dir = 1; //diagonal dreapta } }
Desenare
Desenarea pe ecran se face doar atunci cand este necesara si doar intr-o anumita zona. Astfel daca doar bila se misca pe ecran, numai pixelii pentru bila vor fi redesenati. In acest mod functiile pentru desenare s-au complicat (trebuie sa se testeze daca mai e ceva in zona in care desenez pentru a nu-l sterge din greseala) dar s-au eliminat in mare parte acele flickere determinate de lcd_clear() si redesenare integrala.
Am obtinut un software functional simplist dar numai in simulare. Partea hardware nu am reusit sa o implementez, conectarea lcd-ului de Nokia s-a dovedit prea meticuloasa pentru aptitudinile mele de lipit. Singura “realizare” in acest domeniu fiind o arsura pe brat.
S-a implementat un singur nivel. Pentru mai multe functionalitati este necesara o memorie mai mare.
In continuare voi prezenta starile prin care trece jocul cu screenshot-uri din simulare.
Pornire program
Se afiseaza un mesaj de intampinare si apoi se asteapta ca utilizatorul sa apese pe un buton pentru a porni jocul.
In joc
Jucatorul controleaza pad-ul din partea de jos a ecranului.
Sfarsit de joc
La finalul jocului se afiseaza un mesaj corespunzator (daca a castigat sau nu) precum si numarul de puncte. Daca s-a incheiat cu succes sunt 1200 de puncte iar daca este game over numarul de puncte variaza in functie de numar de blocuri distruse.
Se asteapta 5 secunde apoi aplicatia se reseteaza.
Proiectul a fost interesant, ma refer la desenarea si comunicarea cu lcd-ul Nokia. Acest lucru l-am realizat insa spre final cand mi-am dat seama ca nu i-am acordat timpul necesar pentru a-l duce pana la capat.
Arhiva de mai jos contine sursele, makefile, schema si libraria pentru Proteus.
333ca_simonastefan_breakout.zip