This shows you the differences between two versions of the page.
pm:prj2024:apredescu:octavian.poenaru [2024/05/23 20:20] octavian.poenaru [Hardware Design] |
pm:prj2024:apredescu:octavian.poenaru [2024/05/27 23:09] (current) octavian.poenaru [Bibliografie] |
||
---|---|---|---|
Line 13: | Line 13: | ||
* Buzzer-ul va scoate sunete în momentul în care mingea atinge paleta sau atunci când este înscris un punct 8-). | * Buzzer-ul va scoate sunete în momentul în care mingea atinge paleta sau atunci când este înscris un punct 8-). | ||
* LED-ul verde se va aprinde pentru jucătorul care a înscris punctul iar cel roșu pentru pierzător. | * LED-ul verde se va aprinde pentru jucătorul care a înscris punctul iar cel roșu pentru pierzător. | ||
- | * Cel care are 5 puncte este câștigător iar LED-urile vor pâlpâi de câteva ori . | + | * Cel care are 7 puncte este câștigător iar LED-urile vor pâlpâi de câteva ori . |
</note> | </note> | ||
Line 44: | Line 44: | ||
+ | ===== Software Design ===== | ||
+ | Dezvoltarea codului am realizat-o in Arduino IDE | ||
+ | Pe partea de software am folosit bibliotecile: | ||
+ | - Wire.h: librărie standard pentru comunicarea I2C pe plăcile Arduino. | ||
+ | - Adafruit_GFX.h: librărie grafică utilizată pentru a desena forme și texte pe display-uri. | ||
+ | - Adafruit_SSD1306.h: ibrărie specifică pentru controlul display-ului OLED SSD1306 prin intermediul comunicării I2C. | ||
+ | |||
+ | ==Algoritmi și Structuri Implementate:== | ||
+ | |||
+ | **Setări Inițiale:** | ||
+ | |||
+ | * Configurarea pinilor pentru butoane și LED-uri. | ||
+ | * Inițializarea comunicării I2C cu display-ul OLED. | ||
+ | * Afișarea ecranului de start cu un splash screen "Arduino Pong". | ||
+ | |||
+ | |||
+ | **Controlul Jocului:** | ||
+ | |||
+ | * Butoanele sunt utilizate pentru a controla mișcarea paletelor stânga și dreapta. | ||
+ | * Algoritm pentru actualizarea pozițiilor paletelor bazat pe intrările butoanelor. | ||
+ | * Algoritm pentru actualizarea poziției mingii și detectarea coliziunilor cu paletele și marginile ecranului. | ||
+ | * Algoritm pentru gestionarea punctajului și resetarea jocului atunci când un jucător câștigă. | ||
+ | |||
+ | |||
+ | **Desenarea Jocului:** | ||
+ | |||
+ | * Desenarea mingii, paletelor și scorurilor pe display-ul OLED folosind funcțiile oferite de Adafruit_GFX și Adafruit_SSD1306. | ||
+ | |||
+ | |||
+ | **Gestionarea Vitezei și Poziției Mingi:** | ||
+ | |||
+ | * Funcții pentru ajustarea vitezei mingii după fiecare coliziune cu o paletă sau cu marginile ecranului. | ||
+ | * Funcții pentru resetarea poziției mingii și ajustarea dimensiunilor paletelor după fiecare punct marcat. | ||
+ | |||
+ | |||
+ | **Anunțarea Câștigătorului:** | ||
+ | * Funcție pentru anunțarea câștigătorului prin clipirea unui LED specific de mai multe ori. | ||
+ | |||
+ | |||
+ | |||
+ | ==== Surse și Funcții Implementate: ==== | ||
+ | |||
+ | === Setup și Loop: === | ||
+ | |||
+ | <code cpp> | ||
+ | void setup() { | ||
+ | pinMode(l_up_button, INPUT); | ||
+ | pinMode(l_down_button, INPUT); | ||
+ | pinMode(r_up_button, INPUT); | ||
+ | pinMode(r_down_button, INPUT); | ||
+ | pinMode(led1, OUTPUT); | ||
+ | pinMode(led2, OUTPUT); | ||
+ | Serial.begin(9600); | ||
+ | randomSeed(analogRead(0)); | ||
+ | |||
+ | display.begin(SSD1306_SWITCHCAPVCC, 0x3C); | ||
+ | display.display(); | ||
+ | display.clearDisplay(); | ||
+ | |||
+ | display.setTextSize(1); | ||
+ | display.setTextColor(WHITE); | ||
+ | display.setCursor(display.width() / 2 - 20, 0); | ||
+ | display.println("Arduino"); | ||
+ | display.setCursor(display.width() / 2 - 10, 8); | ||
+ | display.println("Pong"); | ||
+ | display.display(); | ||
+ | delay(2000); | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | unsigned long currentMillis = millis(); | ||
+ | if (currentMillis - previousMillis >= interval) { | ||
+ | previousMillis = currentMillis; | ||
+ | updateGame(); | ||
+ | drawGame(); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | === Funcții pentru Actualizarea Jocului și Desenare: === | ||
+ | |||
+ | <code cpp> | ||
+ | void updateGame() { | ||
+ | if (l_score >= max_score) { | ||
+ | announce_winner(led1); | ||
+ | reset_game(); | ||
+ | return; | ||
+ | } else if (r_score >= max_score) { | ||
+ | announce_winner(led2); | ||
+ | reset_game(); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | if (digitalRead(l_up_button) && l_pos > 0) { l_pos -= 2; } | ||
+ | else if (digitalRead(l_down_button) && l_pos < (y_pixels - l_paddle_height)) { l_pos += 2; } | ||
+ | |||
+ | if (digitalRead(r_up_button) && r_pos > 0) { r_pos -= 2; } | ||
+ | else if (digitalRead(r_down_button) && r_pos < (y_pixels - r_paddle_height)) { r_pos += 2; } | ||
+ | |||
+ | x_pos += x_vel; | ||
+ | y_pos += y_vel; | ||
+ | |||
+ | if (y_pos >= y_pixels - 1 || y_pos <= 0) { y_vel = -y_vel; adjust_speed(); } | ||
+ | if (ball_on_right_paddle()) { | ||
+ | x_vel = -x_vel; | ||
+ | adjust_speed(); | ||
+ | tone(speakerPin, 300, 100); | ||
+ | } else if (ball_on_left_paddle()) { | ||
+ | x_vel = -x_vel; | ||
+ | adjust_speed(); | ||
+ | tone(speakerPin, 250, 100); | ||
+ | } | ||
+ | |||
+ | if (x_pos >= x_pixels - 1) { | ||
+ | ball_reset(false); | ||
+ | l_score += 1; | ||
+ | tone(speakerPin, 50, 100); | ||
+ | digitalWrite(led1, HIGH); | ||
+ | delay(500); | ||
+ | digitalWrite(led1, LOW); | ||
+ | } else if (x_pos <= 0) { | ||
+ | ball_reset(true); | ||
+ | r_score += 1; | ||
+ | tone(speakerPin, 50, 100); | ||
+ | digitalWrite(led2, HIGH); | ||
+ | delay(500); | ||
+ | digitalWrite(led2, LOW); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void drawGame() { | ||
+ | display.clearDisplay(); | ||
+ | display.drawPixel(x_pos, y_pos, WHITE); | ||
+ | display.fillRect(0, l_pos, paddle_width, l_paddle_height, WHITE); | ||
+ | display.fillRect(x_pixels - paddle_width, r_pos, paddle_width, r_paddle_height, WHITE); | ||
+ | |||
+ | display.setTextSize(1); | ||
+ | display.setTextColor(WHITE); | ||
+ | display.setCursor(display.width() / 4, 0); | ||
+ | display.println(l_score); | ||
+ | display.setCursor(display.width() * 3 / 4, 0); | ||
+ | display.println(r_score); | ||
+ | |||
+ | display.display(); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | === Funcții de Utilitate: === | ||
+ | <code cpp> | ||
+ | bool ball_on_right_paddle() { | ||
+ | return ((x_pos + x_vel) >= x_pixels - paddle_width - 1 && y_pos >= r_pos && y_pos <= (r_pos + r_paddle_height)); | ||
+ | } | ||
+ | |||
+ | bool ball_on_left_paddle() { | ||
+ | return ((x_pos + x_vel) <= paddle_width - 1 && y_pos >= l_pos && y_pos <= (l_pos + l_paddle_height)); | ||
+ | } | ||
+ | |||
+ | void ball_reset(bool left) { | ||
+ | y_pos = random(display.height()); | ||
+ | y_vel = random(2) ? 3 : -3; | ||
+ | |||
+ | if (left) { | ||
+ | x_vel = 2; | ||
+ | x_pos = paddle_width; | ||
+ | } else { | ||
+ | x_vel = -2; | ||
+ | x_pos = display.width() - paddle_width - 1; | ||
+ | } | ||
+ | |||
+ | adjust_paddles(); | ||
+ | } | ||
+ | |||
+ | void adjust_speed() { | ||
+ | if (x_vel > 0 && x_vel < max_vel) { | ||
+ | x_vel += 1; | ||
+ | } else if (x_vel < 0 && x_vel > -max_vel) { | ||
+ | x_vel -= 1; | ||
+ | } | ||
+ | |||
+ | if (y_vel > 0 && y_vel < max_vel) { | ||
+ | y_vel += 1; | ||
+ | } else if (y_vel < 0 && y_vel > -max_vel) { | ||
+ | y_vel -= 1; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void adjust_paddles() { | ||
+ | int new_height = random(5, 15); | ||
+ | int mode = random(3); | ||
+ | |||
+ | if (mode == 0) { | ||
+ | l_paddle_height = new_height; | ||
+ | r_paddle_height = new_height; | ||
+ | } else if (mode == 1) { | ||
+ | l_paddle_height = new_height; | ||
+ | r_paddle_height = paddle_height; | ||
+ | } else { | ||
+ | l_paddle_height = paddle_height; | ||
+ | r_paddle_height = new_height; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void announce_winner(int winner_led) { | ||
+ | for (int i = 0; i < 6; i++) { | ||
+ | digitalWrite(winner_led, HIGH); | ||
+ | delay(250); | ||
+ | digitalWrite(winner_led, LOW); | ||
+ | delay(250); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void reset_game() { | ||
+ | l_score = 0; | ||
+ | r_score = 0; | ||
+ | l_paddle_height = 10; | ||
+ | r_paddle_height = 10; | ||
+ | ball_reset(random(2)); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ===== Download ===== | ||
+ | |||
+ | {{:pm:prj2024:apredescu:pong.zip|}} | ||
+ | |||
+ | ===== Jurnal ===== | ||
+ | |||
+ | <note tip> | ||
+ | |||
+ | * 28.04.2023 - Am finalizat ideea de bază a jocului, am creat flow-ul și am ales piesele potrivite pentru circuit | ||
+ | * 11.05.2023 - Am comandat piesele pentru proiect. | ||
+ | * 12.05.2023 - Mi-au venit piesele pentru hardware. | ||
+ | * 15.05.2023 - Am început să lucrez la hardware , iar o parte din breadboard nu merge. Laborantul mi-a spus ca unul din breadboard-uri era mai vechi și trebuiau legate părțile între ele , după cum se poate observa în poză . | ||
+ | * 16.05.2023 - Deja terminasem cu hardware-ul , așa că m-am apucat din timp de software, știind că acolo va fi mai greu. | ||
+ | * 23.05.2023 - Aproape termin cu soft-ul , momentan întâmpin niște bug-uri , bila merge prea lent , paletele prea rapid iar jocul e prea ușor. | ||
+ | * 25.05.2023 - Ajung într-un punct în care codul este suficient de ok , am mărit bila și velocitatea ei , am făcut o funcție de reset , am făcut ca paletele să aibă dimensiuni random atunci când un jucator dă gol , pentru a fi mai provocator jocul. | ||
+ | </note> | ||
+ | ===== Concluzii ===== | ||
+ | A fost un proiect destul de interesant, mi-a plăcut să lucrez la el , exceptând momentele în care a trebuit să fac debug pentru chestii simple. | ||
+ | |||
+ | ===== Bibliografie===== | ||
+ | |||
+ | * [[https://www.arduino.cc/reference/en/libraries/adafruit-gfx-library/]] | ||
+ | * [[https://www.arduino.cc/reference/en/language/functions/communication/wire/]] | ||
+ | * [[https://github.com/adafruit/Adafruit_SSD1306]] |