Snake & Tetris

Tibuleac Andrei
343C4

Introducere

In cadrul proiectului am implementat jocurile clasice snake si tetris folosind microcontroller-ul ATMega16 si un ecran LCD de Nokia3310

Hardware

Componente aditionale placii de baza: - ecran LCD Nokia3310 - condensator 10uF - 4 butoane push

Schema legaturii ecran - microcontroller - butoane in ISIS

Pinii folositi pentru comunicare ecran - microcontroller:

  • LCD_DC_PIN = PB3
  • LCD_CE_PIN = PB4
  • SPI_MOSI_PIN = PB5
  • LCD_RST_PIN = PB6
  • SPI_CLK_PIN = PB7

Pinii folositi pentru butoane (snake/tetris: pin)

  • LEFT/DOWN : PD0
  • UP/LEFT : PD1
  • RIGHT/ROTATE :PD2
  • DOWN/RIGHT :PD3

Software

Am folosit libraria pcd8544 pentru interfatarea cu ecranul LCD Mediul de dezvoltare folosit: Programmer's Notepad

Implementare snake

Pozitiile segmentelor sarpelui si bucatile de hrana sunt retinute intr-o structura de tip:
struct coord { byte x, y; };

Segmentele sarpelui sunt tinute intr-un vector de astfel de structuri.

Functii:

int check_food_pos(): returneaza 1 daca pozitia hranei nu se intersecteaza cu unul din segmentele sarpelui, altfel returneaza 0.

void generate_food(): genereaza aleator o pozitie noua pentru hrana, pana cand aceasta este intr-o pozitie acceptata de functia check_food_pos().

void checButton(int *direction): scrie in direction directia corespunzatoare butonului apasat.

void initSnake(): initializeaza sarpele cu pozitia si dimensiunea initiale.

int checkSnake(): verifica daca sarpele a lovit un zid sau s-a lovit de propriul corp; mai verifica, de asemenea, daca sarpele a ajuns la mancare, caz in care dimensiunea acestuia creste si se semnaleaza faptul ca trebuie generata o nou segment hrana

void showSnake(): afiseaza pe ecran segmentele sarpelui si hrana

void clearSnake(): sterge de pe ecran segmentele sarpelui si hrana

void moveSnake() muta fiecare segment al sarpelui; capul este mutat conform directiei curente a sarpelui, iar fiecare alt segment se muta pe pozitia celui din fata sa

int checkDirection(int old, int current): este apelata dupa apasarea unui buton; verifica daca sarpele poate merge in directia indicata; daca old si current au aceeasi directie sau directii opuse, directia curenta ramane neschimbata

Algoritmul principal (se executa cat timp flag-ul dead nu este 1):

  • se citeste directia noua folosind checkButton()
  • se verifica directia dorita folosind checkDirection()
  • se apeleaza moveSnake() pentru a muta sarpele in directia curenta
  • se verifica noua pozitie folosind checkSnake()
  • daca sarpele a murit, se seteaza flag-ul dead
  • altfel, se afiseaza sarpele pe ecran
  • daca la apelarea checkSnake() sarpele a consumat hrana, se genereaza o noua pozitie corespunzatoare pentru hrana

Implementare tetris

Structuri de date:

Pentru piesa in miscare am definit structura:
typedef struct piece
{
sbyte x, y;
sbyte left_clearance, right_clearance;
piece_type type;
int segment_offset_x[3];
int segment_offset_y[3];
}piece_t;

sbyte - tip de date signed char

x, y → pozitia unui segment al piesei (care va fi considerat segmentul principal al piesei)

left_clearance, right_clearance → distanta dintre segmentul principal si cel mai din stanga, respectiv dreapta, segment al piesei (initial le foloseam pentru a pastra piesa in limitele tablei de joc, dar nu le-am mai folosit, optand pentru alta metoda)

type: tipul piesei; in total 19 tipuri: cele 7 piese si rotatiile lor (4 rotatii pentru piesele de tip L, J si T; 2 rotatii pentru piesele de tip I, S si Z; o rotatioe pentru piesa de tip O)

segment_offset_x/y[3]: vectori de 3 elemente ce reprezinta offset-urile pe axa x, respectiv y, ale celorlalte 3 segmente ale piesei fata de segmentul principla

Pentru a retine segmentele deja existente in joc (cele care nu apartin piesei curente in miscare), am folosit o tabela de 25 de elemente (cate unul pentru fiecare rand) de tip short int. Coloanele sunt reprezentate de bitii 0:9 ai acestor elemente.

* initial folosisem o matrice 25×10 de elemente de tip byte, dar am avut bug-uri ciudate

Functii

void set_piece_offsets(piece_t *p, piece_type t): functie ce seteaza offset-urile segmentelor in functie de fiecare tip de piesa in parte

void draw_square3x3(sbyte x, sbyte y): functie ce deseneaza un patrat 3×3 pe ecran cu coltul stanga sus in pozitia data de x si y;

void draw_border(): deseneaza cele doua linii ce delimiteaza zona de joc

void draw_piece(piece_t *p): deseneaza piesa data ca parametru; se deseneaza fiecare segment in parte, folosing functia draw_square3x3()

void init_table(): initializeaza elementele tabelei de joc cu 0 (oarecum redundant, deoarece tabela este declarata global, dar am vrut sa fiu sigur)

void draw_table(): deseneaza segmentele din tabela (conform bitilor din fiecare element al vectorului corespunzator tabelei)

sbyte check_position(piece_t *p): verifica daca piesa data ca parametru se afla intr-o pozitie valida (nici un segment nu este in afara limitelor tabelei si nici un segment nu se intersecteaza cu alt segment din tabela)

void try_rotate(piece_t *p, piece_type rotation): incearca sa transforme piesa primita ca parametru in tipul rotation (ales in asa fel incat sa fie aceeasi piesa dar cu alta rotatie) - creeaza o piesa noua cu aceeasi parametrii ca si p
- atribuie piesei noi tipul rotation
- se verifica piesa cu functia check_position()
- daca piesa noua este intr-o pozitie valida, o inlocuieste pe cea veche
- altfel, se repeta procedura pe aceeasi piesa cu pozitia shiftata pe orizontala la stanga si la dreapta (am ales sa fac aceasta verificare pentru cazurile cand se incearca rotatia cand o piesa este lipita de un perete)

void rotate(piece_t *p): apeleaza try_rotation() cu parametrul rotation ales corespunzator tipului piesei p

sbyte can_advance(piece_t *p): verifica daca piesa mai poate avansa, asemanator cu try_rotate: - creeaza o piesa noua cu aceeasi parametrii ca si p
- decrementeaza atributul y al piesei noi
- verifica piesa cu check_position()
- daca piesa noua este intr-o pozitie valida, o inlocuieste pe cea veche si returneaza 1
- altfel, returneaza 0

void try_move(piece_t *p, sbyte offset): incearca deplasarea piesei pe orizontala cu offset(care poate fi 1 sau -1); asemanator cu functia can_advance

void copy_to_table(piece_t *p): copiaza segmentele piesei trimise ca parametru in tabela jocului

void check_lines(): foloseste o variabila globala, marked_lines, pentru a marca liniile pline (cu cate un patrat pe fiecare pozitie)
- variabila este initializata cu 0
- se verifica fiecare element din tabela daca este o linie completa (daca este egal cu 0x03FF: 10 biti de 1); daca da, bitul corespunzator liniei in marked_lines este setat pe 1

void remove_lines(): foloseste variabila globala marked_lines pentru a elimina liniile pline;

Algoritm principal

Cat timp nu s-a terminat jocul:
- daca nu exista o piesa curenta in joc, piesa curenta devine piesa next, iar piesa next este generata aleator (piesa next este cea afisata in dreapta zonei de joc)
* se verifica piesa noua cu functia can_advance(), daca esueaza testul, inseamna ca nu poate fi generata (s-a umplut ecranul pana la varf) iar jocul se termina
- in intervalul de timp dintre o avansare in jos a piesei, se trateaza eventualele apasari de buton (miscare pe orizontala, rotatie, coborare rapida)
- se verifica folosind functia can_advance() daca piesa se poate misca pe verticala in jos; daca nu, aceasta este copiata in tabela de joc cu copy_to_table() si se eventualele linii pline cu functiile check_lines() si remove_lines()

Rezultate

Am realizat cu succes atat partea hardware, cat si ambele jocuri.

Bibliografie/Resurse

Pentru codul sursa pentru partea de Snake am pornit de la codul din proiectul lui Vlad Berteanu din 2010 caruia i-am adus cateva modificari.

Schema ISIS este, de asemenea, preluata din acelasi proiect.

Download

Codul sursa si schema ISIS:

proiect_pm_tibuleac_andrei_v2.zip

pm/prj2012/dtudose/snake_tetris.txt · Last modified: 2021/04/14 17:07 (external edit)
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0