Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2024:vstoica:gheorghe.grosu [2024/05/21 23:34]
gheorghe.grosu [Software Design]
pm:prj2024:vstoica:gheorghe.grosu [2024/05/26 18:13] (current)
gheorghe.grosu [Jurnal]
Line 49: Line 49:
  
 {{:​pm:​prj2024:​vstoica:​snake_2024_schem_v4.png?​600|}} {{:​pm:​prj2024:​vstoica:​snake_2024_schem_v4.png?​600|}}
 +
 +{{:​pm:​prj2024:​vstoica:​img_3423.jpeg?​600|}}
  
  
Line 57: Line 59:
 1. Mediu de dezvoltare: 1. Mediu de dezvoltare:
 - **Platformă de dezvoltare**:​ Arduino IDE - **Platformă de dezvoltare**:​ Arduino IDE
-  - Arduino IDE este utilizat pentru scrierea, compilarea și încărcarea firmware-ului pe un microcontroller Arduino.+    ​Arduino IDE este utilizat pentru scrierea, compilarea și încărcarea firmware-ului pe un microcontroller Arduino.
  
 2. Librării şi surse 3rd-party: 2. Librării şi surse 3rd-party:
Line 70: Line 72:
  - Functia `tone()` este utilizată pentru a genera sunete pe pinul difuzorului.  - Functia `tone()` este utilizată pentru a genera sunete pe pinul difuzorului.
  
-#### 3. Algoritmi şi structuri implementate:​+3. Algoritmi şi structuri implementate:​
 - **Structuri de date**: - **Structuri de date**:
-  - `Joystick`: Monitorizează direcția joystick-ului pentru ​controlul ​șarpelui. + 
-  ​- ​`GameState`: Gestionează stările jocului și timpul de cadru pentru fiecare stare. +**`Joystick`** 
-  ​- ​`Snake`: Păstrează lungimea și pozițiile șarpelui.+Structura `Joystick` se ocupă de citirea pozițiilor analogice ale joystick-ului ​și de calcularea direcțiilor următoare ​pentru ​deplasarea ​șarpelui. 
 + 
 +**`GameState`** 
 + 
 +Structura `GameState` gestionează stările jocului și timpul de cadru pentru fiecare stare, facilitând tranzițiile între stări și verificarea momentului potrivit pentru actualizarea jocului
 + 
 +**`Snake` 
 +** 
 + 
 +Structura `Snake` gestionează pozițiile șarpelui, lungimea sa și funcțiile pentru resetare, mișcare și creștere. De asemenea, verifică dacă șarpele a colizionat cu el însuși. 
 + 
 +Șarpele este reprezentat prin structura `Snake`, care conține: 
 +* **`length`**: ​lungimea ​șarpelui. 
 +* **`positions`**:​ array de tip `byte` ce stochează pozițiile fiecărui segment al șarpelui. 
 + 
 +Motive pentru această reprezentare:​ 
 + 
 +1. **Eficiență Memorie**: Folosirea `byte` ocupă doar 1 octet, economisind memorie RAM limitată pe Arduino. 
 + 
 +2. **Simplitate ​și Performanță**:​ Acces rapid și simplu la pozițiile șarpelui ​pentru operațiuni de mișcare și creștere. 
 + 
 +3. **Gestionare Ușoară a Lungimii**: Lungimea și pozițiile sunt ușor de manipulat pentru actualizări rapide în timpul jocului. 
  
 - **Algoritmi**:​ - **Algoritmi**:​
-  ​**Controlul ​jocului**: Monitorizează intrările de la joystick pentru a controla ​direcția șarpelui ​și pentru a trece între diferitele stări ale jocului+   - Controlul direcției șarpelui ​pe baza intrărilor de la joystick
-  **Detectarea ​coliziunilor**: Verifică coliziunile șarpelui ​cu obstacolele, ​pereții și corpul ​propriu+   ​Verificarea ​coliziunilor cu pereții, obstacolele ​și corpul ​șarpelui
-  **Generarea aleatorie a poziției merelor**: Utilizează funcția `random()` pentru a genera poziții aleatorii pentru mere.+   - Gestionarea creșterii șarpelui și actualizarea scorului. 
 +   - Generarea aleatorie a pozițiilor merelor
 +   - Stocarea și citirea scorurilor maxime din EEPROM.
  
-#### 4. Surse şi funcţii ​implementate+Funcțiile ​implementate
-- **Setup-ul inițial**:​ +
-  ```cpp +
-  void setup() { +
-    Serial.begin(9600);​ +
-    randomSeed(analogRead(5));​ +
-    pinMode(SW, INPUT_PULLUP);​ +
-    pinMode(PIN_RED,​ OUTPUT); +
-    pinMode(PIN_GREEN,​ OUTPUT); +
-    tft.initR(INITR_BLACKTAB);​ +
-    level_select_init();​ +
-    last_frame_time = millis(); +
-    curr_note_start_time = 0; +
-  } +
-  ``` +
-  - Initializează serialul pentru debugging. +
-  - Configurează pinurile pentru joystick, LED-uri și difuzor. +
-  - Inițializează ecranul TFT și structurile de date.+
  
-- **Starea de selecție a nivelului**: +Funcții principale:
-  ```cpp +
-  void state_level_select() { +
-    if (joystick.dir_y == 1) { +
-      selected_level = (selected_level + 1) % 3; +
-    } else if (joystick.dir_y == -1) { +
-      selected_level = (selected_level - 1); +
-      if (selected_level < 0) selected_level = 2; +
-    } +
-    tft.fillRect(64,​ 40, 20, 60, ST7735_BLACK);​ +
-    tft.fillTriangle(80,​ 44 + 18 * selected_level,​ 80, 60 + 18 * selected_level,​ 64, 52 + 18 * selected_level,​ ST7735_WHITE);​ +
-    if (digitalRead(SW) == LOW) { +
-      gameState.transition_to(LEVEL_INIT,​ LEVEL_INIT_FRAME_TIME);​ +
-    } +
-  } +
-  ``` +
-  - Permite utilizatorului să selecteze nivelul dorit utilizând joystick-ul și butonul.+
  
-**Inițializarea nivelului**: +  ​ **setup()** 
-  ```cpp +   ​Inițializează comunicarea serială. 
-  void state_level_init() +   ​Configurează pinii pentru joystick șLED-urile RGB
-    tft.fillScreen(ST7735_BLACK);​ +   ​Inițializează ecranul TFT
-    score = 0; +   ​Afișează ecranul de selecție a nivelului
-    max_score = 100; +   ​- Inițializează ​starea ​și timpul de cadru pentru joc.
-    snake.reset();​ +
-    empty_spaces = N_TILES ​M_TILES - snake.length;​ +
-    memset(tiles,​ 0, sizeof(tiles));​ +
-    if (selected_level >= 1) { +
-      for (int i = 0; i < N_TILES; i++) { +
-        renderIfDifferent(i,​ OBSTACLE);​ +
-        renderIfDifferent(N_TILES ​M_TILES - 1 - i, OBSTACLE); +
-        ​renderIfDifferent(i * M_TILES, OBSTACLE);​ +
-        renderIfDifferent(i * M_TILES + M_TILES ​1, OBSTACLE);​ +
-      } +
-      ​empty_spaces ​-= N_TILES * 4; +
-    } +
-    if (selected_level == 2) { +
-      for (int = 0; i < sizeof(level3_obstacles);​ i++) { +
-        int col = level3_obstacles[i] % M_TILES;  +
-        int row = level3_obstacles[i] / N_TILES; +
-        for (int j = -1; j <= 1; j++) { +
-          renderIfDifferent((row + j) * M_TILES + col, OBSTACLE);​ +
-        } +
-        for (int k = -1; k <= 1; k++) { +
-          renderIfDifferent(row * M_TILES + col + k, OBSTACLE);​ +
-        } +
-        empty_spaces -= 3; +
-      } +
-    } +
-    if (random(0, 10) == 0) { +
-      renderIfDifferent(get_random_pos(),​ RED_APPLE);​ +
-    } else { +
-      renderIfDifferent(get_random_pos(),​ APPLE); +
-    } +
-    renderIfDifferent(snake.positions[snake.length - 1], SNAKE_HEAD);​ +
-    for (int i = 0; i < snake.length ​1; i++) { +
-      renderIfDifferent(snake.positions[i],​ SNAKE_BODY);​ +
-    } +
-    eeprom_position = selected_level * 4; +
-    EEPROM.get(eeprom_position,​ high_score);​ +
-    gameState.transition_to(LEVEL_RUNNING,​ LEVEL_RUNNING_FRAME_TIME);​ +
-  } +
-  ``` +
-  ​Configurează elementele grafică și obstacolele pentru nivelul selectat+
-  - Inițializează ​pozițiile șarpelui ​și merele pe ecran.+
  
-**Rularea nivelului**: +* **loop()** 
-  ```cpp +   ​Verifică dacă trebuie să actualizeze starea jocului pe baza timpului de cadru
-  void state_level_running() +   ​Citește direcțiile de la joystick. 
-    int new_head_x = joystick.next_x(get_x(snake.positions[snake.length - 1])); +   ​Execută funcțiile corespunzătoare fiecărei stări (selecție nivel, inițializare nivel, rulare nivel, game over).
-    int new_head_y = joystick.next_y(get_y(snake.positions[snake.length - 1])); +
-    byte next_pos = new_head_y ​M_TILES + new_head_x; +
-    if (snake.has_collided_with_self(next_pos)) { +
-      gameState.transition_to(GAME_OVER,​ GAME_OVER_FRAME_TIME);​ +
-      return; +
-    } +
-    if (score != max_score) { +
-      score += 10; +
-      if (score < 500) { +
-        analogWrite(PIN_GREEN,​ score / 4); +
-      } +
-    } +
-    if (tiles[next_pos] == APPLE || tiles[next_pos] == RED_APPLE) { +
-      renderIfDifferent(snake.positions[snake.length ​1], SNAKE_BODY);​ +
-      snake.grow(next_pos);​ +
-      ​renderIfDifferent(snake.positions[snake.length ​1], SNAKE_HEAD);​ +
-      empty_spaces--;​ +
-      renderIfDifferent(get_random_pos(),​ APPLE); +
-      if (tiles[next_pos] == RED_APPLE) { +
-        max_score += 100; +
-      } else { +
-        max_score += 50; +
-      } +
-      tone(SPEAKER_PIN,​ APPLE_EAT_TONE,​ APPLE_EAT_DURATION);​ +
-      return; +
-    } +
-    if (tiles[next_pos] == OBSTACLE) { +
-      gameState.transition_to(GAME_OVER,​ GAME_OVER_FRAME_TIME);​ +
-    } +
-    renderIfDifferent(snake.positions[0],​ GRASS); +
-    renderIfDifferent(snake.positions[snake.length - 1], SNAKE_BODY);​ +
-    snake.move(next_pos);​ +
-    renderIfDifferent(snake.positions[snake.length - 1], SNAKE_HEAD);​ +
-  } +
-  ``` +
-  - Monitorizează ​și actualizează pozițiile ​șarpelui în funcție de intrările ​de la joystick. +
-  Verifică coliziunile și actualizează scorul în funcție ​de interacțiunea cu merele.+
  
-**Finalul jocului**+**Funcții de stare:**
-  ```cpp +
-  void state_game_over() { +
-    if (score > high_score) { +
-      high_score = score; +
-      EEPROM.put(eeprom_position,​ high_score);​ +
-    } +
-    digitalWrite(PIN_RED,​ HIGH); +
-    tft.fillScreen(ST7735_RED);​ +
-    tft.setCursor(15,​ 60); +
-    tft.setTextSize(2);​ +
-    tft.println("​YOU LOST"​);​ +
-    tft.setTextSize(1);​ +
-    tft.setCursor(10,​ 90); +
-    tft.println("​Your points " + String(score));​ +
-    tft.setCursor(10,​ 110); +
-    tft.println("​Best score " + String(high_score));​ +
-  } +
-  ``` +
-  - Afișează mesajul de finalizare a jocului și scorurile. +
-  - Salvează scorurile maxime în EEPROM pentru a le menține între sesiunile de joc.+
  
-**Ciclu principal**: +* **state_level_select()** 
-  ```cpp +   - Permite utilizatorului să aleagă nivelul dorit folosind ​joystick-ul
-  void loop() { +   ​Afișează săgeata de selecție pe ecran. 
-    if (gameState.should_update()) { +   - Trecerea la starea ​de inițializare a nivelului atunci când utilizatorul apasă butonul ​de selecție.
-      gameState.update_time();​ +
-      ​joystick.set_dirs(); +
-      ​switch (gameState.state) { +
-        case LEVEL_SELECT:​ state_level_select();​ break; +
-        case LEVEL_INIT: state_level_init();​ break; +
-        case LEVEL_RUNNING:​ state_level_running();​ break; +
-        case GAME_OVER: state_game_over();​ break; +
-      } +
-    } +
-  } +
-  ``` +
-  ​Actualizează starea jocului ​și procesează intrările utilizatorului și logica jocului în funcție de timpul ​de cadru.+
  
-### Concluzie +* **state_level_init()** 
-Acest design modular +   - Inițializează nivelul selectat, resetând șarpele și plasând obstacole și mere pe hartă. 
-===== Rezultate Obţinute =====+   - Trecerea la starea de rulare a nivelului.
  
-<note tip> +* **state_level_running()** 
-Care au fost rezultatele obţinute ​în urma realizării proiectului vostru+   - Actualizează poziția șarpelui pe baza direcțiilor de la joystick. 
-</​note>​+   - Verifică coliziunile și gestionează creșterea șarpelui. 
 +   - Actualizează scorul și generează sunete atunci când șarpele mănâncă un măr. 
 +   - Trecerea la starea de game over în caz de coliziune. 
 + 
 +* **state_game_over()** 
 +   - Afișează scorul final și scorul maxim pe ecran
 +   - Salvează scorul maxim în EEPROM dacă este cazul. 
 +   - Afișează un mesaj de finalizare a jocului. 
 + 
 +**Funcții utilitare:​** 
 + 
 +1. **level_select_init()** 
 +   * Afișează ecranul de selecție a nivelului. 
 + 
 +2. **renderIfDifferent(int pos, int tile)** 
 +   * Redă graficul corespunzător pentru un tile dacă este diferit de cel precedent. 
 + 
 +3. **render_grass(int pos_x, int pos_y)** 
 +   * Redă grafica pentru iarbă. 
 + 
 +4. **render_snake_head(int pos_x, int pos_y)** 
 +   * Redă grafica pentru capul șarpelui. 
 + 
 +5. **render_snake_body(int pos_x, int pos_y)** 
 +   * Redă grafica pentru corpul șarpelui. 
 + 
 +6. **render_apple(int pos_x, int pos_y)** 
 +   * Redă grafica pentru un măr. 
 + 
 +7. **render_red_apple(int pos_x, int pos_y)** 
 +   * Redă grafica pentru un măr roșu. 
 + 
 +8. **render_obstacle(int pos_x, int pos_y)** 
 +   * Redă grafica pentru un obstacol. 
 + 
 +9. **get_random_pos()** 
 +   * Generează o poziție aleatorie pentru plasarea unui măr pe hartă. 
 + 
 +===== Rezultate Obţinute ===== 
 +{{:​pm:​prj2024:​vstoica:​snk3_gif.gif?​250|}} {{:​pm:​prj2024:​vstoica:​snk2_gif.gif?​250|}}{{:​pm:​prj2024:​vstoica:​snk_gif.gif?​250|}}
  
 ===== Concluzii ===== ===== Concluzii =====
Line 260: Line 182:
  
 <note warning> <note warning>
-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**.+ 
 +{{:pm:prj2024:vstoica:snake.zip|}} 
 </​note>​ </​note>​
  
Line 272: Line 195:
   * 02/05/2024 - Crearea paginii proiectului si completarea partiala a acesteia   * 02/05/2024 - Crearea paginii proiectului si completarea partiala a acesteia
   * 12/05/2024 - Adaugarea schemei electrice si a schemei hardware   * 12/05/2024 - Adaugarea schemei electrice si a schemei hardware
 +  * 22/05/2024 - Adaugarea software designului
 +  * 24/05/2024 - Finisare proiect
 </​note>​ </​note>​
  
pm/prj2024/vstoica/gheorghe.grosu.1716323698.txt.gz · Last modified: 2024/05/21 23:34 by gheorghe.grosu
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