This shows you the differences between two versions of the page.
pm:prj2024:vstoica:andrei.petrea1210 [2024/05/25 22:30] andrei.petrea1210 [Software Design] |
pm:prj2024:vstoica:andrei.petrea1210 [2024/05/27 00:19] (current) andrei.petrea1210 [Bibliografie/Resurse] |
||
---|---|---|---|
Line 60: | Line 60: | ||
=== Descrierea implementarii === | === Descrierea implementarii === | ||
+ | |||
+ | == Structura unui obiect == | ||
+ | Pentru a opera mai usor cu logica jocului, mi-am creat structura //PacmanObject//, care contine 4 campuri | ||
+ | * x -> abscisa obiectului | ||
+ | * y -> ordonata obiectului | ||
+ | * draw -> flag pentru afisarea la ecran | ||
+ | * symbol -> ce afisez la ecran | ||
+ | |||
+ | <code cpp> | ||
+ | // Symbols depending on object type | ||
+ | #define PACMAN "C" | ||
+ | #define FOOD "*" | ||
+ | #define ENEMY "#" | ||
+ | |||
+ | struct PacmanObject { | ||
+ | int16_t x; | ||
+ | int16_t y; | ||
+ | bool draw; | ||
+ | String symbol; | ||
+ | }; | ||
+ | </code> | ||
== Start-up screen == | == Start-up screen == | ||
Line 80: | Line 101: | ||
== Game Loop == | == Game Loop == | ||
+ | Ca sa inceapa jocul, jucatorul trebuie sa apese butonul de START (butonul din centru), care va crea o noua arena, plasand PacMan-ul in centru ei, si plasand 4 inamici si 7 puncte aleatoriu pe harta. | ||
+ | <code cpp> | ||
+ | void loop() | ||
+ | { | ||
+ | int value = analogRead(A0); | ||
+ | if (!gameStarted) { | ||
+ | if (checkRange(value, 260, 330)) { | ||
+ | gameStarted = true; | ||
+ | gameOver = false; | ||
+ | ateAll = false; | ||
+ | score = 0; | ||
+ | initBoard(); | ||
+ | analogWrite(PIN_RED, 0); | ||
+ | analogWrite(PIN_BLUE, 0); | ||
+ | analogWrite(PIN_GREEN, 64); | ||
+ | } | ||
+ | } | ||
+ | // Rest of code... | ||
+ | } | ||
+ | </code> | ||
+ | Pentru realizarea randomizarii pozitiilor, am folosit functiile //rand// si //srand// din biblioteca standard C, seed-ul pe care l-am ales fiind obtinut prin citirea unui pin analogic neconectat (in cazul meu, A1). | ||
+ | <code cpp> | ||
+ | void setup() | ||
+ | { | ||
+ | // Rest of code... | ||
+ | srand(analogRead(A1)); | ||
+ | } | ||
+ | </code> | ||
+ | Odata intrat in joc, ne putem deplasa //UP//, //DOWN//, //LEFT// si //RIGHT// prin apasarea celor 4 butoane, dispuse conform celor 4 puncte cardinale. In functie de care buton a fost apasat, voi apela functia //move//, care are ca argument, deplasarea pe care i-o voi da PacMan-ului. | ||
+ | <code cpp> | ||
+ | void loop() | ||
+ | { | ||
+ | // Rest of code... | ||
+ | if (!gameOver) { | ||
+ | draw(); | ||
+ | if (checkRange(value, 120, 170)) { | ||
+ | move(0, -1); | ||
+ | } else if (checkRange(value, 190, 230)) { | ||
+ | move(-1, 0); | ||
+ | } else if (checkRange(value, 420, 500)) { | ||
+ | move(1, 0); | ||
+ | } else if (checkRange(value, 900, 1024)) { | ||
+ | move(0, 1); | ||
+ | } | ||
+ | } | ||
+ | // Rest of code... | ||
+ | } | ||
+ | </code> | ||
- | ===== Rezultate Obţinute ===== | + | In functia //move//, voi muta PacMan-ul la pozitia noua, si voi calcula folosind functia //checkCollision//, daca ma intersectez cu obiectul de tip //FOOD// sau cu //ENEMY//. Ma voi folosi si de functia //checkRange//, pentru a oferi toleranta la detectia coliziunii. |
- | <note tip> | + | <code cpp> |
- | Care au fost rezultatele obţinute în urma realizării proiectului vostru. | + | bool checkCollision(PacmanObject obj1, PacmanObject obj2) { |
- | </note> | + | return (checkRange(obj1.x, obj2.x - 2, obj2.x + 2) && checkRange(obj1.y, obj2.y - 2, obj2.y + 2) && checkRange(obj2.x, obj1.x - 2, obj1.x + 2) && checkRange(obj2.y, obj1.y - 2, obj1.y + 2)); |
+ | } | ||
+ | |||
+ | bool checkRange(int val, int low, int high) { | ||
+ | return (val >= low && val <= high); | ||
+ | } | ||
+ | </code> | ||
- | ===== Concluzii ===== | + | Inedit, pentru inamici, am folosit un algoritm de tip **[[https://en.wikipedia.org/wiki/Hill_climbing|Hill-Climbing]]**, care este apelat atunci cand jucatorul face o mutare, facand ca acestia sa se deplaseze catre PacMan. Fiecare inamic se va uita la starile sale vecine (//UP//, //DOWN//, //LEFT//, //RIGHT// in ordinea aceasta) si va alege prima stare mai apropiata decat pozitia sa curenta, folosind distanta Manhattan ca euristica. |
- | ===== Download ===== | + | <code cpp> |
+ | void move(int16_t dx, int16_t dy) | ||
+ | { | ||
+ | // Rest of code... | ||
+ | for (i = 0; i < NR_ENEMIES; i++) { | ||
+ | int8_t j, k; | ||
+ | int16_t currDistance = manhattanDistance(pacMan, enemies[i]); | ||
+ | PacmanObject aux; | ||
+ | for (j = -1; j <= 1; j++) { | ||
+ | bool ok = true; | ||
+ | for (k = -1; k <= 1; k++) { | ||
+ | if (abs(j) != abs(k)) { | ||
+ | aux.x = enemies[i].x + j; | ||
+ | aux.y = enemies[i].y + k; | ||
+ | int16_t distance = manhattanDistance(pacMan, aux); | ||
+ | if (distance < currDistance) { | ||
+ | enemies[i].x = aux.x; | ||
+ | enemies[i].y = aux.y; | ||
+ | ok = false; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | if (!ok) { | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
- | <note warning> | + | int16_t manhattanDistance(PacmanObject obj1, PacmanObject obj2) { |
- | 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ă ;-). | + | return (abs(obj2.x - obj1.x) + abs(obj2.y - obj1.y)); |
+ | } | ||
+ | </code> | ||
+ | |||
+ | |||
+ | == Final screen == | ||
+ | |||
+ | La final, jucatorul ori a colectat toate punctele ori a fost ucis de catre inamic. In functie de cele 2 urmari, se va afisa la ecran un mesaj corespunzator, se va schimba culoarea led-ului intr-una care reflecta rezultatul final si | ||
+ | se va pune la speaker o melodie aferenta. | ||
+ | |||
+ | <code cpp> | ||
+ | void loop() | ||
+ | { | ||
+ | // Rest of code... | ||
+ | TFTscreen.fillScreen(TFT_BLACK); | ||
+ | char scoreSir[11]; | ||
+ | sprintf(scoreSir, "Scor: %d\n", score); | ||
+ | if (ateAll) { | ||
+ | TFTscreen.text("Ati castigat! :)", 15, 50); | ||
+ | TFTscreen.text(scoreSir, 40, 70); | ||
+ | analogWrite(PIN_GREEN, 0); | ||
+ | analogWrite(PIN_BLUE, 64); | ||
+ | playPacmanIntro(); | ||
+ | } else { | ||
+ | TFTscreen.text("Ati pierdut! :(", 15, 50); | ||
+ | TFTscreen.text(scoreSir, 40, 70); | ||
+ | analogWrite(PIN_GREEN, 0); | ||
+ | analogWrite(PIN_RED, 64); | ||
+ | playFailedSong(); | ||
+ | } | ||
+ | gameStarted = false; | ||
+ | // Rest of code... | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ===== Concluzii ===== | ||
+ | * Proiectul a fost amuzant de facut (exceptand partea hardware :( ), si acum simt ca inteleg mai bine arhitectura calculatoarelor | ||
+ | * Nu pot sa folosesc memoria la fel ca si pe calculator, deoarece am foarte putina memorie si se umple foarte repede | ||
+ | * Sa va uitati de 10 ori in datasheet sa verificati ca ati legat bine firele :) | ||
+ | * Sa va aveti planuri cum o sa arate proiectul, ca sa nu va cumparati piese degeaba si sa va cumparati piese de calitate | ||
+ | |||
+ | ===== Rezultate Obţinute ===== | ||
- | 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**. | + | <html> |
- | </note> | + | <iframe width="560" height="315" src="https://www.youtube.com/embed/M0we7dr7Ifs?si=FwVCBkxV57mRdraP" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> |
+ | </html> | ||
===== Jurnal ===== | ===== Jurnal ===== | ||
Line 109: | Line 256: | ||
* **19.05** - Adaugat legarea initiala | * **19.05** - Adaugat legarea initiala | ||
* **21.05** - Adaugat design software initial + bibliografie + legarea finala | * **21.05** - Adaugat design software initial + bibliografie + legarea finala | ||
+ | * **25.05** - Finalizat design software + pagina OCW | ||
===== Bibliografie/Resurse ===== | ===== Bibliografie/Resurse ===== | ||
Line 115: | Line 263: | ||
* [[https://docs.arduino.cc/resources/datasheets/A000066-datasheet.pdf|Arduino UNO R3 Datasheet]] | * [[https://docs.arduino.cc/resources/datasheets/A000066-datasheet.pdf|Arduino UNO R3 Datasheet]] | ||
* [[https://www.openhacks.com/uploadsproductos/tutorial_display_tft.pdf|KMR 1.8" TFT LCD Datasheet]] | * [[https://www.openhacks.com/uploadsproductos/tutorial_display_tft.pdf|KMR 1.8" TFT LCD Datasheet]] | ||
+ | * [[https://www.youtube.com/watch?v=FGqRiPqg4Ds|TUTORIAL: How to work with a 1.8" SPI TFT with strange incorrect labelling!]] | ||
+ | * [[https://www.instructables.com/Accessing-5-buttons-through-1-Arduino-pin-Revisi/| Accessing 5 Buttons Through 1 Arduino Pin - Revisited]] | ||
=== Resurse Software === | === Resurse Software === | ||
Line 120: | Line 270: | ||
* [[https://www.arduino.cc/en/software| Arduino IDE]] | * [[https://www.arduino.cc/en/software| Arduino IDE]] | ||
* [[https://github.com/robsoncouto/arduino-songs| Arduino Songs]] | * [[https://github.com/robsoncouto/arduino-songs| Arduino Songs]] | ||
+ | * [[https://en.wikipedia.org/wiki/Hill_climbing| Hill climbing]] | ||
+ | ===== Download ===== | ||
+ | <html><a class="media mediafile mf_zip" href="https://ocw.cs.pub.ro/courses/_media/pm/prj2024/vstoica/petrea_andrei_pacman.zip">Download archive</a></html> | ||
<html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | ||