This shows you the differences between two versions of the page.
|
gp:laboratoare:06 [2026/03/28 15:08] maria_anca.balutoiu [Simularea unei Lumi] |
gp:laboratoare:06 [2026/04/08 09:07] (current) maria_anca.balutoiu [Generarea procedurală de NPCs] |
||
|---|---|---|---|
| Line 11: | Line 11: | ||
| === Atribute derivate din clasă === | === Atribute derivate din clasă === | ||
| - | Fiecare clasă definește **intervale de bază** pentru atributele NPC-urilor. Randomizarea se aplică în interiorul acestor intervale, nu global — un Mage va fi mereu mai slab fizic decât un Warrior, indiferent de roll. Exemplu: | + | Fiecare clasă definește **intervale de bază** pentru atributele NPC-urilor. Randomizarea se aplică în interiorul acestor intervale, nu global; un Mage va fi mereu mai slab fizic decât un Warrior, indiferent de roll. Exemplu: |
| ^ Class ^ HP ^ Damage ^ Armor ^ | ^ Class ^ HP ^ Damage ^ Armor ^ | ||
| Line 132: | Line 132: | ||
| - **Generatorul de NPC-uri:** Fiecare NPC se generează prin selecția ponderată a clasei și aplicarea multiplicatorilor de personalitate. Pentru început, se generează numele din două liste independente, apoi selectează clasa, apoi se selectează personalitatea uniform aleatoriu, iar în final se generează atributele de bază din intervalele clasei și se înmulțesc cu multiplicatorii de personalitate. | - **Generatorul de NPC-uri:** Fiecare NPC se generează prin selecția ponderată a clasei și aplicarea multiplicatorilor de personalitate. Pentru început, se generează numele din două liste independente, apoi selectează clasa, apoi se selectează personalitatea uniform aleatoriu, iar în final se generează atributele de bază din intervalele clasei și se înmulțesc cu multiplicatorii de personalitate. | ||
| - **ItemGenerator:** Pentru calculul rarității se urmează același model de selecție ponderată. După ce raritatea e determinată, se calculează bugetul total (''BASE_BUDGET × rarityMultiplier''), se generează un număr aleator dintr-un interval predefinit (de exemplu, [0.4, 0.7]) pentru damage, iar restul bugetului merge la durabilitate. Numele itemului se construiește procedural dintr-un prefix aleatoriu și un sufix dependent de tip. Abilitățile speciale se adaugă pentru Epic (una) și Legendary (două distincte). | - **ItemGenerator:** Pentru calculul rarității se urmează același model de selecție ponderată. După ce raritatea e determinată, se calculează bugetul total (''BASE_BUDGET × rarityMultiplier''), se generează un număr aleator dintr-un interval predefinit (de exemplu, [0.4, 0.7]) pentru damage, iar restul bugetului merge la durabilitate. Numele itemului se construiește procedural dintr-un prefix aleatoriu și un sufix dependent de tip. Abilitățile speciale se adaugă pentru Epic (una) și Legendary (două distincte). | ||
| - | <hidden> | + | - **Sistemul de Relații:** Relațiile sunt stocate ca valori float într-un anumit interval predefinit (de exemplu, intervalul [−100, +100]). Relația directă se actualizează cu delta, iar relația inversă cu ''delta × 0.7'', ambele cu clamp la intervalul predefinit. |
| - | === Pasul 4: RelationshipMatrix === | + | - **NPC Agent:** Se implementează arborele de decizie din tabelul de relații, ținând cont și de lista vecinilor, modificatorul locației curente, în ordinea exactă a priorităților. Se calculează damage-ul primit și se verifică dacă NPC-ul a murit. |
| - | + | - **Jurnal Narativ:** Se selectează aleatoriu din template-urile existente pentru a se afișa acțiunile NPC-urilor. | |
| - | ''RelationshipMatrix'' nu este ''MonoBehaviour'' — este o clasă C# simplă instanțiată de ''WorldSimulator''. Intern, relațiile sunt stocate într-un ''Dictionary<(string, string), float>'' unde cheia este perechea ordonată de nume. Metoda ''Initialize()'' populează toate perechile posibile cu valoarea 0. Metoda ''Modify()'' actualizează relația directă cu delta și relația inversă cu ''delta × 0.7'', ambele cu clamp la [−100, 100]. Metodele ''GetEnemies()'' și ''GetAllies()'' filtrează lista de NPC-uri dintr-o locație după pragul de relație. | + | - **Main World Simulator:** Sistemul așteaptă ''tickInterval'' secunde între tick-uri. La fiecare ''zi'' nouă, se iterează printre toți agenții vii, aplică damge-ul agentului, aplică decizia luată de agent. Simularea se termină când rămâne cel mult un NPC în viață sau se epuizează zilele maxime. |
| - | + | ||
| - | === Pasul 5: NPCAgent === | + | |
| - | + | ||
| - | ''NPCAgent'' împachetează un ''NPCData'' și expune două metode publice. ''Decide()'' primește contextul complet (lista vecinilor, matricea de relații, ID-urile locațiilor, modificatorul locației curente) și returnează o structură ''Decision'' cu tipul acțiunii, ținta opțională și locația destinație pentru Flee/Move. Logica implementează arborele de decizie din tabel, în ordinea exactă a priorităților. ''TakeDamage()'' calculează damage-ul real după reducerea de armor (''Mathf.Max(1f, rawDamage - armor × 0.5f)'') și returnează ''true'' dacă NPC-ul a murit. | + | |
| - | + | ||
| - | === Pasul 6: NarrativeJournal === | + | |
| - | + | ||
| - | ''NarrativeJournal'' este o clasă C# simplă cu câte un array de template-uri per tip de acțiune. Fiecare metodă ''Generate*Entry()'' selectează aleatoriu un template și aplică ''string.Replace()'' în lanț pentru fiecare variabilă. Metoda ''GenerateSummary()'' construiește sumarul final al simulării: câte zile a durat, cine a supraviețuit, lista celor căzuți și inventarul supraviețuitorului. Intrările de tip ''Idle'' se înregistrează condiționat (''Random.value < 0.2f'') pentru a nu polua jurnalul. | + | |
| - | + | ||
| - | === Pasul 7: WorldSimulator === | + | |
| - | + | ||
| - | ''WorldSimulator'' este un ''MonoBehaviour'' care pornește o coroutine ''SimulationLoop()'' ce așteaptă ''tickInterval'' secunde între tick-uri. La fiecare ''AdvanceDay()'', iterează prin toți agenții vii, aplică modificatorul locației pe damage-ul agentului (temporar, restaurat după tick), cere decizia prin ''agent.Decide()'', execută acțiunea prin ''ApplyDecision()'' și aplică bonusul de co-prezență pentru toți din aceeași locație. ''ApplyDecision()'' gestionează toate cele 5 tipuri de acțiune, inclusiv notificarea martorilor la ucidere. Simularea se termină când rămâne cel mult un NPC în viață sau se epuizează zilele maxime. | + | |
| - | + | ||
| - | Comunicarea cu UI-ul se face exclusiv prin evenimente C#: ''OnJournalEntry'', ''OnDayAdvanced'', ''OnNPCDied'' și ''OnSimulationEnd'' — astfel simularea nu știe nimic despre UI și poate fi testată independent. | + | |
| - | + | ||
| - | <note tip>Conectați evenimentele în ''Awake()'' din ''SimulationPanel'', nu în ''Start()'', pentru a garanta că nu pierdeți niciun eveniment dacă simularea pornește în același frame.</note> | + | |
| - | </hidden> | + | |
| ==== Tasks ==== | ==== Tasks ==== | ||
| - Creați un NPC generator simplist în care: | - Creați un NPC generator simplist în care: | ||
| * Un NPC este definit printr-o combinație aleatoare de nume, clasă, viață, damage. | * Un NPC este definit printr-o combinație aleatoare de nume, clasă, viață, damage. | ||
| - | * Fiecare NPC va avea și o trasătură aleatoare de personalitate, care îi va afecta comportamentul. | + | * Clasa este selectată prin distribuție ponderată. |
| + | * Fiecare NPC va avea și o trasătură aleatoare de personalitate, care modifică numeric atributele de bază. | ||
| * Pe baza clasei asociate, fiecare NPC va avea un portret afișat pe ecran. | * Pe baza clasei asociate, fiecare NPC va avea un portret afișat pe ecran. | ||
| * Se generează un nou NPC și se afișează pe ecran la apăsarea unui buton. | * Se generează un nou NPC și se afișează pe ecran la apăsarea unui buton. | ||
| - Creați un generator de armură și arme în care: | - Creați un generator de armură și arme în care: | ||
| - | * Un item este definit printr-un tip, o raritate, damage și durabilitate. | + | * Un item este definit printr-un tip, o raritate, damage și durabilitate generate din **stat budget**. |
| - | * Item-ele mai rare au și câte o abilitate specială precum poison, lifesteal, fire damage, ice slow. | + | * Itemele Epic și Legendary au abilități speciale cu parametri proprii generați în intervale (exemple abilități: poison, lifesteal, fire damage, ice slow). |
| * Se generează un nou item și se afișează pe ecran la apăsarea unui buton. | * Se generează un nou item și se afișează pe ecran la apăsarea unui buton. | ||
| + | * Numele itemului se generează procedural (prefix + tip). | ||
| * În funcție de raritatea item-ului, scrisul de pe ecran va avea altă culoare. | * În funcție de raritatea item-ului, scrisul de pe ecran va avea altă culoare. | ||
| + | - Implementați simularea unei lumi procedurale: | ||
| + | * Generați 4–6 NPC-uri și distribuiți-le aleatoriu în 5 locații predefinite. | ||
| + | * La apăsarea butonului ''Advance Day'', fiecare NPC execută o acțiune bazată pe personalitate, HP curent și relațiile cu vecinii din aceeași locație. | ||
| + | * Sistemul de relații [−100, +100] se actualizează după fiecare interacțiune și influențează deciziile viitoare. | ||
| + | * Fiecare acțiune generează o linie de text narativ din template-uri cu minim 3 variante per tip. | ||
| + | * Simularea se oprește când rămâne un singur NPC în viață sau după 10 zile și afișează un sumar procedural. | ||
| - **Bonus 1.** Creați un meniu prin care să puteți scrola prin toate personajele și obiectele generate. Rezultatele generări se vor salva pentru a fi accesibile și la rulări ulterioare ale aplicației. Jucătorul va putea redenumi NPCs și item-urile generate. | - **Bonus 1.** Creați un meniu prin care să puteți scrola prin toate personajele și obiectele generate. Rezultatele generări se vor salva pentru a fi accesibile și la rulări ulterioare ale aplicației. Jucătorul va putea redenumi NPCs și item-urile generate. | ||
| - **Bonus 2.** Pentru fiecare item afișați "rarity stars" în dreptul numelui. Adăugați un efect de animație pentru cel mai rar tip de item. | - **Bonus 2.** Pentru fiecare item afișați "rarity stars" în dreptul numelui. Adăugați un efect de animație pentru cel mai rar tip de item. | ||
| + | - **Bonus 3.** Adăugați o hartă vizuală simplă (grid sau icoane) care arată locația curentă a fiecărui NPC și se actualizează la fiecare tick. | ||