This shows you the differences between two versions of the page.
egc:teme:2023:01 [2023/10/29 20:30] andrei.lambru |
egc:teme:2023:01 [2023/11/03 20:25] (current) andrei.lambru [Reguli generale de joc] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | <hidden> | ||
===== Tema 1 - Romburi vs hexagoane ===== | ===== Tema 1 - Romburi vs hexagoane ===== | ||
* **Responsabili:** Andrei Voicu, Mihnea Tudor, Anca Cristea, Cristian Lambru | * **Responsabili:** Andrei Voicu, Mihnea Tudor, Anca Cristea, Cristian Lambru | ||
Line 18: | Line 17: | ||
<note tip> | <note tip> | ||
- | Implementarea din demo-ul pus la dispoziție nu va mai identifica corect poziția cursorului, în situația în care se modifică dimensiunea ferestrei. Aceasta rămâne de implementat la latitudinea voastră și este considerată cerință bonus :) . | + | Implementarea din demo-ul pus la dispoziție nu identifică corect poziția cursorului, în situația în care se modifică dimensiunea ferestrei. Aceasta rămâne de implementat la latitudinea voastră și este considerată cerință bonus :) . |
</note> | </note> | ||
Line 49: | Line 48: | ||
=== Comportament romburi și inamici === | === Comportament romburi și inamici === | ||
- | Din partea dreaptă, la intervale aleatoare de timp, se deplasează un inamic de-alungul unei linii alese aleator. Inamicul face parte din unul din cele 4 tipuri posibile. În situația în care un romb de același tip se regăsește într-una din cele 3 celule ale liniei, acesta începe să lanseze proiectile la intervale regulate. În situația în care există și **alte tipuri** de romburi pe linie, acestea **nu lansează proiectile**. | + | Din partea dreaptă, la intervale aleatoare de timp, se deplasează un inamic de-alungul unei linii alese aleator. Inamicul face parte din unul din cele 4 tipuri posibile. În situația în care un romb de același tip se regăsește într-una din cele 3 celule ale liniei, acesta începe să lanseze proiectile la intervale regulate. În situația în care un romb **nu are un inamic de același tip cu el pe linie**, rombul respectiv **nu lansează proiectile**, chiar dacă pe linie sunt inamici de alte tipuri. |
+ | |||
+ | <hidden> | ||
+ | În situația în care există și **alte tipuri** de romburi pe linie, acestea din urmă **nu lansează proiectile**. | ||
+ | </hidden> | ||
=== GUI === | === GUI === | ||
Line 80: | Line 83: | ||
* Comportament de joc (50p in total) | * Comportament de joc (50p in total) | ||
* Detecția selecției unei celule de joc prin apăsarea butonului stânga al mouse-ului și plasarea unui romb în celulă 10p | * Detecția selecției unei celule de joc prin apăsarea butonului stânga al mouse-ului și plasarea unui romb în celulă 10p | ||
- | * Apariție inamici la intervale regulate 5p | + | * Apariție inamici la intervale aleatoare 5p |
* Detecția faptului că un inamic a traversat în totalitate o linie 5p | * Detecția faptului că un inamic a traversat în totalitate o linie 5p | ||
* Apariție proiectil de lânga un romb în momentul în care există inamic pe linie 10p | * Apariție proiectil de lânga un romb în momentul în care există inamic pe linie 10p | ||
Line 107: | Line 110: | ||
* Detecția coliziunii proiectil-inamic, doar în situația în care proiectilul are aceeași culoare ca cea a inamicului 2.5p | * Detecția coliziunii proiectil-inamic, doar în situația în care proiectilul are aceeași culoare ca cea a inamicului 2.5p | ||
- | ==== Detalii de implementare ==== | + | ===== Detalii de implementare ===== |
==== Construcție elemente vizuale ==== | ==== Construcție elemente vizuale ==== | ||
Line 182: | Line 185: | ||
În momentul în care un proiectil se intersectează cu un inamic, acesta din urmă dispare din scenă printr-o animație de micșorare față de centrul comun al celor două hexagoane care formează geometria inamicului. Această animație poate fi realizată, similar cu cea de micșorare a rombului, printr-o transformare de scalare. Proiectilul dispare și el la intersecția lui cu inamicul, doar că nu realizează nicio animație, doar nu se mai afișează de la cadrul următor după detecția intersecției. | În momentul în care un proiectil se intersectează cu un inamic, acesta din urmă dispare din scenă printr-o animație de micșorare față de centrul comun al celor două hexagoane care formează geometria inamicului. Această animație poate fi realizată, similar cu cea de micșorare a rombului, printr-o transformare de scalare. Proiectilul dispare și el la intersecția lui cu inamicul, doar că nu realizează nicio animație, doar nu se mai afișează de la cadrul următor după detecția intersecției. | ||
- | === Detecție coliziuni === | + | ==== Detecție coliziuni ==== |
- | + | ||
- | ==== Detecție coliziuni între obiecte ==== | + | |
Mecanismul de detecție a coliziunilor între diverse obiecte din scenă reprezintă un feature esențial în cam orice joc la care vă puteți gândi. În [[https://www.youtube.com/watch?v=fiShX2pTz9A|Pong]] trebuie verificată coliziunea mingii, atât cu ecranul jocului, cât și cu "paleta" fiecărui jucător. În jocurile [[https://www.youtube.com/watch?v=QLF0FXcW25E|Mario]], trebuie verificată coliziunea dintre jucător și toate obiectele înconjurătoare: cuburi, inamici, power-ups etc. În jocul nostru, avem nevoie de o implementare puțin mai simplificată a coliziunilor. | Mecanismul de detecție a coliziunilor între diverse obiecte din scenă reprezintă un feature esențial în cam orice joc la care vă puteți gândi. În [[https://www.youtube.com/watch?v=fiShX2pTz9A|Pong]] trebuie verificată coliziunea mingii, atât cu ecranul jocului, cât și cu "paleta" fiecărui jucător. În jocurile [[https://www.youtube.com/watch?v=QLF0FXcW25E|Mario]], trebuie verificată coliziunea dintre jucător și toate obiectele înconjurătoare: cuburi, inamici, power-ups etc. În jocul nostru, avem nevoie de o implementare puțin mai simplificată a coliziunilor. | ||
Line 204: | Line 205: | ||
<note important>Aveți grijă cum definiți formele geometrice: proiectil, romb, hexagon. Dacă ați definit obiectul original astfel încât centrul formei geometrice să se afle în punctul (0, 0), atunci centrul cercului va coincide cu centrul formei. Altfel, este posibil să intervină niște deplasări care trebuie luate în calcul. De asemenea, fiți atenți la eventuale rotații și translații ale obiectelor în scenă.</note> | <note important>Aveți grijă cum definiți formele geometrice: proiectil, romb, hexagon. Dacă ați definit obiectul original astfel încât centrul formei geometrice să se afle în punctul (0, 0), atunci centrul cercului va coincide cu centrul formei. Altfel, este posibil să intervină niște deplasări care trebuie luate în calcul. De asemenea, fiți atenți la eventuale rotații și translații ale obiectelor în scenă.</note> | ||
- | ==== Detecție coliziuni între obiecte și cursor ==== | + | ==== Interacțiune jucător ==== |
Un alt aspect esențial este interacțiunea jucătorului cu obiectele din scenă, în acest caz, prin intermediul mouse-ului. Avem două astfel de interacțiuni: | Un alt aspect esențial este interacțiunea jucătorului cu obiectele din scenă, în acest caz, prin intermediul mouse-ului. Avem două astfel de interacțiuni: | ||
* colectarea de resurse, prin apăsarea unui buton pe mouse | * colectarea de resurse, prin apăsarea unui buton pe mouse | ||
* plasarea romburilor în celule, prin intermediul drag & drop | * plasarea romburilor în celule, prin intermediul drag & drop | ||
+ | * ștergerea romburilor din celule | ||
Modul de funcționare este similar cu cel de la coliziunea obiect-obiect, fiind nevoie să determinăm marginile fiecărui obiect. În schimb, în acest caz, trebuie determinată poziția curentă a cursorului pe ecran, după care verificăm dacă se află în interiorul marginilor obiectului. | Modul de funcționare este similar cu cel de la coliziunea obiect-obiect, fiind nevoie să determinăm marginile fiecărui obiect. În schimb, în acest caz, trebuie determinată poziția curentă a cursorului pe ecran, după care verificăm dacă se află în interiorul marginilor obiectului. | ||
Line 216: | Line 218: | ||
<note important>Poziția cursorului pe fereastra jocului are ca punct de origine **colțul din stânga sus**, în timp ce spațiul de joc/logic are ca punct de origine **colțul din stânga jos**. Din acest motiv, pentru a folosi coordonata y a cursorului pentru obiectele din scena de joc, trebuie să utilizăm următorul calcul: //y_scena_joc = 720 - y_cursor//. Valoarea 720 reprezintă înălțimea ferestrei.</note> | <note important>Poziția cursorului pe fereastra jocului are ca punct de origine **colțul din stânga sus**, în timp ce spațiul de joc/logic are ca punct de origine **colțul din stânga jos**. Din acest motiv, pentru a folosi coordonata y a cursorului pentru obiectele din scena de joc, trebuie să utilizăm următorul calcul: //y_scena_joc = 720 - y_cursor//. Valoarea 720 reprezintă înălțimea ferestrei.</note> | ||
- | Pentru coliziunile cursor-obiect, vom folosi dreptunghiuri încadratoare aliniate cu axele (axis-aligned bounding boxes, mai multe detalii [[https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection#axis-aligned_bounding_box|aici]]) pentru obiecte. Pe scurt, ne vom imagina un dreptunghi (în locul cercului de la coliziunile obiect-obiect) cu laturile paralele cu axele Ox și Oy, și cu centrul în cel al obiectului. | + | Pentru detecția situației în care poziția cursorului se află în interiorul unui element vizual din joc, vom folosi dreptunghiuri încadratoare aliniate cu axele (axis-aligned bounding boxes, mai multe detalii [[https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection#axis-aligned_bounding_box|aici]]) pentru obiecte. Pe scurt, ne vom imagina un dreptunghi (în locul cercului de la coliziunile obiect-obiect) cu laturile paralele cu axele Ox și Oy, și cu centrul în cel al obiectului. |
Pentru a verifica apăsarea unui buton de la mouse, când cursorul se află în interiorul unui obiect, trebuie să: | Pentru a verifica apăsarea unui buton de la mouse, când cursorul se află în interiorul unui obiect, trebuie să: | ||
Line 223: | Line 225: | ||
- Verificăm dacă poziția cursorului este între marginile dreptunghiului | - Verificăm dacă poziția cursorului este între marginile dreptunghiului | ||
- | === Drag & drop === | + | ==== Drag & drop ==== |
- | Pentru a plasa un romb pe una dintre celule, acesta trebuie selectat cu mouse-ul din bara romburilor disponibile, dupa care trebuie tras deasupra unei celule **libere**. O celula libera este o celula care nu este deja ocupata de un romb. | + | Pentru a plasa un romb pe una dintre celule, acesta trebuie selectat cu mouse-ul din bara romburilor disponibile, după care trebuie tras deasupra unei celule **libere**. O celulă liberă este o celulă care nu este deja ocupată de un romb. |
- | Pentru a crea acest mecanism, trebuie realizati urmatorii pasi: | + | Pentru a crea acest mecanism, trebuie realizați următorii pași: |
- | - Detectia apasarii butonului stang al mouse-ului | + | - Detecția apăsării butonului stâng al mouse-ului |
- | - Detectia pozitiei cursorului intr-una dintre casutele cu romburi disponibile (pentru care avem suficiente resurse) | + | - Detecția poziției cursorului într-una dintre căsuțele cu romburi disponibile (pentru care avem suficiente resurse) |
- | - Randarea rombului la pozitia cursorului, in fiecare frame, cat timp butonul ramane apasat | + | - Randarea rombului la poziția cursorului, în fiecare frame, cât timp butonul rămâne apăsat |
- | - Detectia eliberarii (release) al aceluiasi buton de mouse (cel stang) | + | - Detecția eliberării (release) al aceluiași buton de mouse (cel stâng) |
- | - Detectia pozitiei cursorului intr-una dintre celulele libere | + | - Detecția poziției cursorului într-una dintre celulele libere |
- | - Plasarea rombului in celula | + | - Plasarea rombului în celulă |
- | - Reducerea resurselor disponibile, in functie de costul rombului | + | - Reducerea resurselor disponibile, în funcție de costul rombului |
{{ :egc:teme:2023:drag-n-drop.gif?300 |}} | {{ :egc:teme:2023:drag-n-drop.gif?300 |}} | ||
- | <note>In cazul in care utilizatorul apasa pe un romb pentru care nu are suficiente resurse, algoritmul se opreste la pasul 2. De asemenea, daca butonul mouse-ului este eliberat intr-o pozitie invalida (oriunde in afara unei celule libere), desenarea rombului la pozitia cursorului este oprita, iar resursele **nu** sunt consumate (practic, plasarea rombului intr-o pozitie invalida nu are niciun efect).</note> | + | <note>În cazul în care utilizatorul apasă pe un romb pentru care nu are suficiente resurse, algoritmul se oprește la pasul 2. De asemenea, dacă butonul mouse-ului este eliberat într-o poziție invalidă (oriunde în afara unei celule libere), desenarea rombului la poziția cursorului este oprită, iar resursele **nu** sunt consumate (practic, plasarea rombului într-o pozitie invalidă nu are niciun efect).</note> |
==== Exemple de funcționalități bonus ==== | ==== Exemple de funcționalități bonus ==== | ||
Line 251: | Line 253: | ||
* Implementare de "niveluri" cu durate stabilite, avansarea la următorul nivel în urma terminării celui anterior | * Implementare de "niveluri" cu durate stabilite, avansarea la următorul nivel în urma terminării celui anterior | ||
* Sistem de "waves" (ca în jocul original): în anumite momente ale jocului, un grup mare de hexagoane este trimis către romburi | * Sistem de "waves" (ca în jocul original): în anumite momente ale jocului, un grup mare de hexagoane este trimis către romburi | ||
- | * Resurse care cad din cer și se așază undeva în scena | + | * Resurse care cad din cer și se așază undeva în scenă |
- | * Lawnmowers, ca în plants vs zombies | + | * Lawnmowers, ca în Plants vs Zombies |
- | * Orice aduce imbunatatiri vizuale jocului | + | * Orice aduce îmbunătățiri vizuale jocului |
- | <note tip>Daca vreti sa functioneze corect detectia si in cazul redimensionarii ferestrei de joc, lucrurile se complica putin. | + | <note tip>Dacă vreți să funcționeze corect detecția în cazul redimensionării ferestrei de joc, se va aplica următoarea abordare: |
- | Initial, daca incepeti cu scheletul din laboratorul 3, spatiul logic coincide 1:1 cu spatiul de vizualizare, adica toate pozitiile obiectelor coincid cu coordonata respectiva de pe ecran. Marginea dreapta a spatiului logic va coincide cu marginea dreapta a ferestrei de joc, adica lungimea ferestrei (resolution.x), iar marginea de sus cu inaltimea ferestrei (resolution.y). | + | Inițial, dacă începeți cu scheletul din laboratorul 3, spațiul logic coincide 1:1 cu spațiul de vizualizare, adică toate pozițiile obiectelor coincid cu coordonata respectivă de pe ecran. Marginea dreaptă a spațiului logic va coincide cu marginea dreaptă a ferestrei de joc, adică lungimea ferestrei (resolution.x), iar marginea de sus cu înălțimea ferestrei (resolution.y). |
- | Sa zicem ca vrem sa jucam in modul fullscreen. Vom nota rezolutia initiala (cea aleasa in functia 'main()') cu (init_width, init_height), iar cea noua cu (new_width, new_height). Spatiul logic ramane cel initial, intre coordonatele (0, 0) si (init_width, init_height), dar spatiul de vizualizare se mareste, fiind intre (0, 0) si (new_width, new_height). De aceea, pentru o functionare corecta, este necesara o transformare fereastra-poarta din noul spatiu de vizualizare in cel initial, pentru a coincide iarasi cu spatiul logic initial. | + | Dacă vrem să redimensionăm fereastra, este nevoie să aplicăm o transformare fereastră-poartă din noua rezoluție în cea inițială. Mai exact, daca notăm noua rezoluție cu coordonatele (new_width, new_height), vrem să traducem noul spațiu de coordonate, cuprins între (0, 0) - (new_width, new_height), în cel inițial (corespunzător celui logic), cuprins între (0, 0) - (1280, 720). De notat este faptul că (1280, 720) este rezoluția inițială a ecranului, și este setată în funcția //main()//. |
- | Aceasta transformare trebuie aplicata pentru oricare alt fragment de cod sau logica ce se folosesc de marginile ecranului.</note> | + | Această transformare trebuie aplicată pentru oricare alt fragment de cod sau logică ce se folosesc de marginile ecranului.</note> |
==== Întrebări și răspunsuri ==== | ==== Întrebări și răspunsuri ==== | ||
Line 288: | Line 290: | ||
</note> | </note> | ||
- | </hidden> |