Table of Contents

Space Defense

Autor: Pogan Alexandru-Mihail

Grupa: 335CA

Îndrumător: Andreea Luca

Introducere

Proiectul constă în implementarea unei versiuni simplificate a jocului Space Impact, folosind o serie de module hardware, conectate la o placă de dezvoltare. Motivul pentru alegerea acestui proiect este dorința de a readuce la viață un joc foarte apreciat în copilărie de cei mai mulți dintre noi, prin intermediul cunoștințelor acumulate în domeniul electronicii dar și a proiectării și programării microcontrollerelor.

Descriere generală

În cadrul jocului, scopul principal este salvarea, din postura unei nave spațiale, a unor tărâmuri îndepărtate din spațiu de diverși inamici, distribuiți pe parcursul mai multor niveluri, acompaniate la final de câte un inamic șef, scorul fiind calculat în funcție de numărul de inamici nimiciți. Pe acest model de proiect, utilizatorul poate controla nava spațială, folosind un joystick. De asemenea, pentru a putea trage în inamici, acesta trebuie să apese pe un buton.

Schema bloc

Conform schematicii propuse, microcontroller-ul leagă o serie de componente hardware, în așa manieră încât să poată juca rolul unui transmițător. Astfel, acesta va putea citi valorile analogice primite de la joystick, pentru a putea calcula, respectiv desena, starea următoare a entităților jocului, numai după ce plăcuța s-a conectat la display-ul ILI9341, prin intermediul protocolului SPI. Tot microcontroller-ul gestionează pin-ul analogic specific buzzer-ului, pentru a putea scoate o serie de sunete salvate în memorie, atât când utilizatorul trage, cât și atunci când se termină nivelul. Modulul RTC, conectat la Arduino este folosit, pentru a îmbunătăți experiența de joc a utilizatorului.

Hardware Design

În vederea realizării design-ului hardware, am decis întâi să testez legarea componentelor la pinii corespunzători, prin intermediul simulatorului de circuite Cirkit Designer [1]. Totuși, printre componente n-am găsit display-ul propus inițial, ST7735, care să fie și compatibil cu funcția de simulare. Așadar, am folosit display-ul ILI9341, inclusiv în cadrul realizării de mână.
În cadrul acestei scheme, prima dată am legat display-ul SPI la microcontroller, folosind o serie de fire tată la tată, pentru a lega pinii specifici protocolului SPI, cu niște porturi digitale, specificate în tabelele cu conexiunile dintre pini.
Din simulator, pare că display-ul funcționează corespunzător, ecranul schimbându-și culoarea și afișând un meniu minimalist al jocului.
Pentru gestionarea miscărilor, joystick-ul este conectat la microcontroller printr-o serie de pini analogici, pentru cele două potențiometre, care controlează abscisa, respectiv ordonata jucătorului, în timp ce pentru buton, se folosește un pin digital, la alegere.
Modulul RTC, este de asemenea conectat la microcontroller, prin intermediul unor fire tată la tată.

Gestionarea conexiunilor pinilor între display și microcontroller

Pin Display Pin Arduino
MOSI(Master Output Slave Input) D11
MISO(Master Input Slave Output) D12
CS(Chip Select) D10
LED(pentru aprinderea ledurilor de pe display) 5V
SCK(slave clock) D13
RST(reset) RESET

Gestionarea conexiunilor pinilor între joystick și microcontroller

Pin Joystick Pin Arduino
VRx(HORZ) A1
VRy(VERT) A0
SW(buton) D6

Gestionarea conexiunilor pinilor între buzzer și microcontroller

Pin Buzzer Pasiv Pin Arduino
S(Output Signal) D8
VCC VCC
GND GND

Gestionarea conexiunilor pinilor între modulul RTC și microcontroller

Pin Buzzer Pasiv Pin Arduino
SCL SCL
SDA SDA

Bill of Materials

Software Design

IDE și biblioteci folosite

Pentru a dezvolta aplicația, am folosit IDE-ul Arduino, utilă inclusiv apriori implementării propriu-zise, datorită posibilității de testare a componentelor legate. De asemenea, am folosit librăria Adafruit_GFX, destinată desenării primitivelor grafice direct din cod, precum și biblioteca Adafruit_9341, având ca dependențe inclusiv Adafruit_GFX și SPI.h, destinată conectării facile a microcontroller-ului la display, prin intermediul programării la nivel înalt, respectiv prin SPI. Pentru a configura modulul RTC am folosit biblioteca Wire.h, pentru a începe conexiune I2C, respectiv biblioteca Rtc_Pcf8563, pentru a prelucra mai usor dispozitivul.

Structuri de date folosite

Ca structuri de date, am folosit o structură în care am salvat informații legate de jucător, cum ar fi viața, precum și poziția, respectiv inamici, cu mențiunea că cei din urmă au un câmp de control, scopul fiind verificarea faptul că nu au fost distruși de jucător. De asemenea, am definit o serie de vectori, în care sunt salvate pozițiile gloanțelor, respectiv a turnurilor, precum și niște limite ale numărului de entități randate, urmând ca noile gloanțe să fie salvate în locul celor, care au ieșit din raza de vizualizare ori s-au ciocnit de inamici, respectiv variabile cu care am implementat bouncing pe butonul joystick-ului.

Logica de tip low-level

Pentru a citi valorile analogice de la pinii alocați joystick-ului, am inițializat convertorul analog-digital, prin intermediul funcțiilor adc_init, respectiv myAnalogRead, cu mențiunea că înainte m-am asigurat că jocul funcționează corespunzător, folosind funcția analogRead. De asemenea, pentru a putea extrage informațiil din canalele analogice, am avut de scăzut din macrourile definite în cod, valoarea aferentă pinului A0. Totodată, pentru a implementa debouncing, m-am folosit inclusiv de registre, cu care am definit timerul 1 al microcontroller-ului, setând prescalerul și tipul de timer, eu în acest caz alegând CTC, precum și duty cycle-ul la 249. În acest fel, am putut defini o întrerupere, care numără milisecunde, în timp ce wrapperul denumit sugestiv, my_millis(), returnează milisecundele respective.

Logica la nivel de aplicație

Din punct de vedere logic, am un loop principal, care gestionează activitatea jucătorului, când acesta se află în cadrul meniului principal, dar care prin apăsarea butonului, să poată ulterior accesa al doilea loop denumit game_loop, responsabil pentru multe sarcini, de la definirea comportamentului navei spațiale, generarea entităților din joc, până la verificarea coliziunilor între acestea, respectiv decizia următoarei stări. După cum se observă, logica aplicației este redusă la un automat finit de stări.

Atunci când jucătorul câștigă sau pierde, va asculta una din melodiile scurte, salvate în memorie.

Totodată, în cod am definit o serie de note muzicale, ce sunt scoase de buzzer de fiecare dată când utilizatorul deschide jocul, precum și o conexiune prin I2C la modului RTC precizat anterior, pentru a prelua datele despre oră, pe care le-am folosit pentru a customiza background-ul jocului. Practic, culoarea cerului se modifică în funcție de datele primite de la RTC, mai exact ora rulării, factorul important care face diferența între macro-ul TIME, respectiv rolul modulului RTC.

Funcția game_loop

Această funcție merită o secțiune proprie, având în vedere numeroasele funcții pe care le îndeplinește. Neavând totuși o modularizare finală, am separat secțiunile relevante, prin intermediul comentariilor. Ca o rutină alternativă de câștigare a meciului, se asigură faptul că atât toate wave-urile de inamici au fost eliminate, în timp ce boss-ul nu mai are setat câmpul is_alive pe true. Necesitatea verificării depășirii wave-urilor vine din simplul fapt că înainte de fiecare joc, boss-ul este inițializat cu 0, folosind funcția memset.
Ca utilizatorul să piardă, se verifică faptul că ori jucătorul a interacționat cu inamicii de dinainte de boss, ori inamicul îl ratează, acesta fiind și scopul jocului, testându-se precizia de tragere a jucătorului. În ambele cazuri, se afișează același mesaj specific pierderii.
De asemenea, funcția se ocupă de mișcarea fiecărei entități, prin mai multe iterații, fiecare având principala condiție de existență, prin verificarea variabilelor de control. În caz afirmativ, fie se verifică eventualele coliziuni nedorite, dar firești, fie se mișcă prin desenarea folosind culoarea cerului în poziția veche, respectiv redesenarea folosind culoarea entității, la noua poziție. În secținea rezultate, am specificat o minusculă problemă.
Totodată, am inclusiv o secvență de acțiuni apelată la apăsarea pe buton, ce are drept scop final generarea de noi gloanțe, respectiv scoaterea unui sunet foarte scurt.

Proiectul de după implementarea software

Rezultate Obţinute

Din punct de vedere al funcționalității, rezultatele proiectului sunt cele așteptate. Însă, din punct de vedere vizual, anumite entități pâlpâie uneori, din cauza modului de desenare a acestora. Totuși, cu niște culori potrivite, zgomotele produse se minimizează.

Concluzii

În cadrul acestui experiment, căutarea pieselor nu a fost cel mai comfortabilă experiență. Totuși, proiectarea, ansamblarea hardware, respectiv implementarea software, au fost părțile cele mai distractive din proiect, făcându-mi plăcere să lucrez. Totodată, am învățat multe lucruri despre programarea embedded, ca urmare a research-ului realizat, concretizat prin analiza datasheet-urilor și a căutării pe internet.

Jurnal

04.05.2025 - Pagina creată
06.05.2025 - Documentație parțială terminată
14.05.2025 - Început asamblare piese
18.05.2025 - Terminată implementarea hardware
24.05.2025 - Terminată prima versiune a implementării software
27.05.2025 - Terminată a doua versiune a implementării software
29.05.2025 - Terminată implementarea finală software, inclusiv comentarii

Bibliografie/Resurse

Schema electrică simulată: https://app.cirkitdesigner.com/project/721a820f-751c-40fc-9a51-9f923cfc1458 Repository implementare software: https://github.com/TheWildWestBoy03/Proiect-PM