This is an old revision of the document!
Snake Game
Autor
Nume: Olaru Alexandru
Grupa: 336CA
Introducere
Fiind pasionat de jocuri video și de console, m-am gândit să retrăiesc bucuria din copilărie atunci când mă jucam Snake pe diversele mini-console de la acea vreme. Așadar, proiectul reprezintă un joc Snake, ce incearcă să fie cât mai asemănător cu un joc pe o consolă portabilă.
Descriere generală
Schema bloc este compusă din urmatoarele componente: un Arduino Uno, o matrice de leduri 8×8, un potențiometru, un buzzer și un joystick.
Matricea de leduri stă in locul ecranului, pe care m-am gândit să îl înlocuiesc, oferindu-i jocului un aspect mai retro. Ledurile aprinse vor semnifica atât șarpele, cât și merele la care acesta va trebui să ajungă. Joystick-ul reprezintă singura modalitate de input a utilizatorului, prin care acesta poate mișca șarpele in 4 direcții: sus, jos, stânga și dreapta. Nu în ultimul rând, prin intermediul potențiometrului se poate regla viteza de joc, iar buzzer-ul este post de difuzor.
Hardware Design
Lista de piese folosite:
Arduino Uno
Breadboard
Modul joystick compatibil Arduino
Matrice 8×8 leduri OKY3523
Buzzer activ OKY0151
Potențiometru rotativ OKY0107
Schema electrica:
Matrice Led:
VCC → 5V
GND → GND
DIN → D12
CS → D11
CLK → D10
Modul Joystick:
GND → GND
VCC → 5V
VRX → A2
VRY → A3
SW → D2
Buzzer:
Potentiometer:
VCC → 5V
VOUT → A5
GND → GND
Software Design
Descrierea codului aplicaţiei:
Structura codului arată astfel:
void setup() {
initialize();
display_snake_message(message_snake);
}
void loop() {
/* Generate food on the display */
generate_food();
/* Scan joystick input and move the snake */
scan_input();
/* Snake movement */
move_snake();
/* Check and handle game over situation */
check_game_over();
}
Implementare:
Funcția initialize() inițializeaza variabilele ce se ocupă cu stările jocului, configureaza ADC(Analog-to-Digital Converter), ce va fi folosit pentru a citi inputul de la joystick, precum și matricea de led-uri.
Funcția display_snake_message(message_snake) va afișa un text dinamic atunci când ”consola” va fi pornită. Acest text va dispărea atunci când se înregistrează un input de la joystick (fie o mișcare a manetei, fie o apăsare a butonului acesteia).
Funcția generate_food() generează mâncarea șarpelui într-un loc random (unul din cele 64 led-uri de pe matrice), care este valid și care nu este ocupat de șarpe. Aceasta se va genera, schimbându-și locul, doar după ce șarpele o va mânca.
Funcția scan_input() va citi input-ul de la joystick, calculând direcția de deplasare a șarpelui. Aceasta se va ocupa și de viteza jocului, care poate fi setată cu ajutorul potențiometrului (cu cât viteza este mai mică, cu atât funcția se termină mai greu, dictând intervalul de timp în care se aprind și se sting led-urile).
Funcția move_snake() este cea care controlează locația în care se află șarpele, în funcție de direcția acestuia. Aceasta tratează cazurile în care șarpele iși mușcă propria coadă, mănâncă mărul, trece prin marginile ”display-ului” și apare din părțile opuse, și se ocupă de aprinderea corespunzătoare a led-urilor în funcție de poziția corpului șarpelui. Atunci când șarpele va mânca mărul, un sunet scurt va fi emis de către buzzer.
Funcția check_game_over() verifica dacă jocul este încheiat, caz în care va afișa un mesaj de ”GAME OVER”. Buzzer-ul va emite un sunet ceva mai lung, pe o tonalitate mai joasă ,iar variabilele de joc vor fi resetate, așteptând input de la joystick pentru ca jocul sa poată fi jucat din nou.
Citirea input-ului de la joystick (valorile X si Y) este făcută folosind ADC:
uint8_t adc_read(uint8_t pin) {
/* Select ADC channel (pin) for conversion */
ADMUX = (ADMUX & 0xF0) | (pin & 0x0F);
/* Start the conversion */
ADCSRA |= (1 << ADSC);
/* Wait for the conversion to complete */
while (ADCSRA & (1 << ADSC));
/* Return the result */
return ADCH;
}
Pentru a aprinde și a stinge led-urile matricei, am folosit funcții din biblioteca https://github.com/wayoda/LedControl, după mai multe încercări de a implementa această funcționalitate ”de mână”, folosind SPI (Serial Peripheral Interface), care este de asemenea folosit și în funcțiile bibliotecii, într-o modalitate asemanătoare cu cea prezentată mai jos:
void send_data(uint8_t address, uint8_t value) {
digitalWrite(CS, LOW);
/* Send address */
SPI.transfer(address);
/* Send value */
SPI.transfer(value);
/* Finish transfer */
digitalWrite(CS, HIGH);
}
Astfel, pinul Chip-Select (CS) este configurat, trimițându-se mai apoi prin SPI adresa registrului lui MAX7219 al matricei de leduri, precum și valoarea dorită. Dacă se dorește aprinderea sau stingerea led-urilor, conform specificațiilor din datasheet (https://www.analog.com/media/en/technical-documentation/data-sheets/max7219-max7221.pdf), adresa va fi un număr de la 1 la 8, reprezentând linia din matrice pe care se vor aplica modificări, iar valoarea un număr de la 0 la 255, indicând ce led-uri vor fi aprinse, respectiv stinse.
Rezultate Obţinute
Concluzii
Download
O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectului: surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună

.
Fişierele se încarcă pe wiki folosind facilitatea Add Images or other files. Namespace-ul în care se încarcă fişierele este de tipul :pm:prj20??:c? sau :pm:prj20??:c?:nume_student (dacă este cazul). Exemplu: Dumitru Alin, 331CC → :pm:prj2009:cc:dumitru_alin.
Jurnal
Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului.
Bibliografie/Resurse
Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe Resurse Software şi Resurse Hardware.
Export to PDF