Motorul Grafic Unity

Cuprins

Capitolul I

Motorul grafic Unity

I.1. Descriere

Unity este un motor de joc pe mai multe platforme, dezvoltat de Unity Technologies și folosite pentru a dezvolta jocuri video pentru PC, console, dispozitive mobile si site-uri. A fost anuntat la inceput doar pentru Mac OS, la Worldwide Developers Conference Apple in 2005, dar a fost extins de atunci pentru a ajunge pe mai mult de 15 platforme,incluzand Windows,Linux,Android etc.

Acest ecosistem este adesea asociat cu jocuri pentru platforma mobile(Android,iOS),dar in ultimul timp a primit o crestere sesizabila in capacitatile grafice ale motorului ceea ce il face o alegere buna pentru orice dezvoltator sau arhictect indiferent de obiectivul lucrarii.

De la aparitia pe piata,pana la ultimele versiuni,Unity a fost creat pentru comunitate si societatea ce inconjoara,dupa cum spune si CEO David Halgason „Un motor cu comunitate mare seamana mai mult cu o miscare sociala decat cu un instrument sofwtare…”,acesta considera ca cea mai importanta inovatie este creearea unei colectivitati in jurul acestui „instrument de creatie”.

I.2. Caracteristici

Unity ofera o gama larga de aptitudini impersionante,inclusiv umbre in timp real si suport multi-ecran.Pentru dezvoltatorii de aplicatii mobile , deschide noi nivele de acces la unelte folosite in orice parte a crearii unui proiect ,de la editare la animatie sau audio

Ultimele versiuni ale uneltei introduce noi trasaturi precum optimizare pentru DirectX 11 si OpenGL ES 3.0 care este baza graficii pe platforma mobile.Un alt obiectiv este crearea unui sistem de fizica cat mai avansat ,iar pe baza acestei gandiri s-a ajuns la sisteme foarte complexe si precise de detectare a coliziunii precum si simularea materialelor textile.

Pe langa fizica 3D ,Unity mai dispune si de fizica 2D folosita in modelarea animatiilor sau a aplicatilor low-end pentru diferite platforme. Suporta si 2d cu capabilitati de sprites este prezente in acest motor grafic

Motorul de joc mai are intgrat si un sistem audio propriu precum si anumite plugins optionale care ajuta la crearea efectelor,sintetizatoarelor etc. toate fiind la indemana utilizatorului.

Unity Android ofera scriptare de programe interfate de aplicatie (API) pentru a accesa diferite date de intrare si setari.Acesta permite chemarea unor functii specializate in C/C++ direct din scriptruri C#.

Unealta aceasta necesita ecosistemul de dezvoltare Android(Android SDK),creeand astfel o legatura stransa intre cele doua programe ,permitand atat creearea cat si testarea proiectelor cu ajutorul emulatorului Android.Tot aici se afla se selecteaza si versiunea sistemului de operare Android cu care se lucreaza.

Aceasta unealta contine si scripturi anti-piraterie care ajuta la crearea unui sistem anti furt si posibilitatea de a bloca anumite functii din aplicatie

Unity suporta assets de la majoritatea aplicatilor de modelare 3D cum ar fi 3D Studio Max,Maya Softimage,Cinema 4D,Blender ceea ce inseamna ca nu exista restrictii la formatul de fisiere suportat.

Unity mai dispune si de un sistem numit Cloud Build care anuleaza limitele hardwareului personal ,utilizand serverele aflate in posesia producatorului pentru a creste eficacitatea dezvoltarii precum si cresterea productivitatii ,valabil atat pentru dezvoltatorii amatori cat si pentru cei profesionisti.

Capitolul II

Unity Tool

II.1. Interfata

Unity Tool dispune de o interfata simpla si intuitiva ,impartita in mai multe tipuri de vizualizari numite „views”,fiecare cu sopuri diferite.Ea prezinta o zona principala a editorului si file(tabs) cu views .Interfata este si personalizabila ,ajutand la crearea unui spatiu de lucru cat mai confortabil si eficient.Acest lucru se face simplu,printr-o miscare drag and drop a unui tab de view,acestea fiind detasabile de zona principala.

Aceste moduri de aranjare a interfetei se pot salva prin modul Save.Acestea pot fi redenumite dupa dorinta.

Interfata este facuta in asa fel sa fie familiara utilizatorilor de siteme de operare Windows/Mac Os

Project Browser

In acest view se poate accesa componentele care apartin proiectului.

In stanga panelului se gasesc structura de foldere a proiectului ca o lista.Cand este selectat un folder continutul acestuia se va extinde in partea dreapta a meniului.Folderul se poate inchide sau deschide la nevoie.

Elemenentele din dreapta au indicatori de format(scriptrui,materiale,sub-foldere etc).Marimea icoanelor se poate schimba cu ajutorul unui slider aflat la baza panelului.

Acest view mai contine si o sectiune „Favorites” unde se pot adauga elemente des folosite pentru a usura lucrul

Browserul dispune si de un motor de cautare puternic care ajuta la gasirea componentelor cand proiectul este masiv sau necunoscut utilizatorului.Acesta are si un filtru care poate cauta doar anumite formate.Elementele se pot cauta si dupa etichete .

Ierarhia

Componentele proiectului sunt numite „GameObjects”.Acestea sunt asezate in ierarhia aflata in stanga-sus a ecranului.O ierarhie contine toate elementele aflate in scena curenta.Fiecare obiect este selectabil si se poate muta pentru a crea o relatie parinte-copil intre restul elementelor.Un obiect copil unui alt obiect parinte dobandeste miscarea si rotatia parintelui.

Bara de instrumente

Tabul de instrumente contine 5 controale de baza fiecare se raporteaza la diferite parti ale editorului

Transform Tools sunt folosite pentru viewul de scene,Transform Gizmo Toggles afecteaza afisajul viewului de scena.Butoanele Play/Pause/Step sunt folosite in viewul de joc.Layers controleaza afisajul obiectelor prezente in scena.Layout controleaza aranjamentul tuturor vizualizarilor.

Scene View

In acest mod se poate interactiona cu orice element al proiectului.Se pot selecta misca decorul ,camera ,personajele si toate GameObjects prezente.Acest view este unul dintre cele mai importante deoarece aici se intampla majoritatea dezvoltarii unui program iar manipularea obiectelor este necesara sa fie cat mai rapida si simpla.Sunt prezente multe controale de navigare precum si scurtaturi de la tastatura sau mouse.Pe langa navigare ,aici se face si rotirea si scalarea obiectelor pe 3 axe.

Din acest mod se pot controla si prezenta sunetului ,luminii,efectelor grafice sau selectarea modului 2D.

Daca se selecteaza un obiect din ierarhie si se doreste concentrarea imaginii pe acest obiect ,acest view dispune de un mod de focus pe obiecte numit Frame Selected ,selectat din meniu Edit.

Modul Flythrough permite utilizatorului sa zboare in prin scena pentru a simula jucarea unui joc.

Aceasta perspectiva ajuta la crearea unui nivel sau a unei atmosfere mai buna ,utilizatorul fiind pus in piela jucatorului.

Game View

Acest mod reprezinta vizualizarea din elementul camera al jocului.El reprezinta imaginea finala a jocului.
Acesta dispune de 3 butoane ,asezate intr-un toolbar,care sunt folosite pentru a vedea si testa produsul final.Modificarile aduse in timpul modului Play sunt temporare ,acestea fiind resetate cand se inchide acest mod.

Editorul isi va reduce din luminozitate in aces mod pentru a spori atentia la vizualizarea jocului.

In Game View se pot schibmba aspectul vizionarii(16:9.16:10 etc) precum si modul Full Screen pentru a vedea mai bine defecte sau alte trasaturi ale proiectului.Butonul Stats prezinta statisticile rularii jocului precum performanta numarul de cadre pe secunda ,utilizarea CPU etc.

Inspector

Jocurile create in Unity sunt alcatuite de mai multe Game Objects care contin diferite elemente cum ar fi scritpuri, sunete, elemente grafice precum lumini.

Inspectorul afiseaza informatii detaliate despre elementul selectat incluzand toate componentele atasate si proprietatile acestora.

De aici se pot modifica functionalitati specializate ale obiectelor din scena.Fiecare proprietate poate fi modificata direct chiar si variabile scripturilor fara a modifica scripturile propriuzise.

Inspectorul poate fi folosit chiar si in timp real pentru a ajunge la solutia perfecta pentru un joc.

Tot de aici se pot adauga componente unui obiect din meniul Add Component.

Desi acestea sunt principalele componente ale interfetei ,Unity dispune si de alte views.

Acestea sunt mai putin importante dar sunt foarte folositoare pentru depanare sau marirea usurintei dezvoltarii unei aplicatii. Acestea variaza de la consola, care arata mesaje,avertismente si errori aparute in timpul rularii sau crearii proiectului, pana la profilator care este folosit pentru a gasi scaderi in performanta sau limitari ale acesteia.

II.2 Grafica

Intelegera graficii este cheia crearii unui simt de profunzime intr-un joc

Iluminatul

Luminile sunt esentiale pentru fiecare scena.Desi texturile si modelele definesc forma si unei scene,lumina definesc culoarea si atmosfera mediului.De obicei se folosesc mai mult de o sursa de lumina in scene.

Luminile se pot adauga din meniul Game Objects. Odata creata ,ea poate fi manipulata ca restul obiectelor.Doar prin schimbarea culorii luminii se poate schimba radical atmosfera unei scene.

Surse de lumina

Luminile punct (point-light)

Sunt localizate intrun punct in spatiu si emit lumina in toate directile.Intensitatea scade odata cu distanta de la sursa ajungand la 0 la dupa o anumita distanta

Acestea sunt folositoare la crearea unei surse de lumina locale cum este lampa .

Luminile spot (spot-lights)

La fel ca luminile punct, acesteea au o locatie specifica dar raza de actiune este doar directionala, in forma de con.Centrul conului arata directia iluminarii.

Acestea sunt deseori folosite pentru a crea surse de lumini artificiale cum sunt lanternele sau farurile de la masina..Directia poate fi controlata prin scriptare sau animatie ceea ce ajuta la crearea unui efect dinamic de iluminare.

Luminile directionale (directional lights)

O sursa de lumina directionala nu are o locatie propriuzisa deci poate fi asezata oriunde in scena.

Toate obiectele sunt iluminate ca si cum lumina ar veni tot timpu din aceasi directie.

Intensitatea luminii nu scade cu distanta.

Aceste surse reprezinta o lumina distanta si mai mare ca si dimensiuni pozitionata in afara lumii jocului.Acestea sunt folosite pentru a simula un soare,dar si pentru a crea umbra pe obiecte fara a specifica exact de unde vine lumina.

Lumina zonala (area light)

Aceasta sursa de lumina este definita ca un dreptunghi in spatiu.Lumina este emisa in toate directile dar doar pe o parte a dreptunghiului.Intensitatea scade dupa o anumita distanta.

Deoarece aceasta metoda de iluminare necesita calcule complexe ,nu se poate folosi in timp real ci doar in modul „lightmaps”.

Fiind iluminat din mai multe obiecte deodata,umbrirea obiectului devine mai subtila decat la celelalte tipuri de surse de iluminat.

Cu aceasta se poate crea iluminare stradala realistica sau a unui pachet de lumini aflat in apropierea jucatorului.Se pot simula si iluminarea unui interior al unei camere cu un efect mai realistic decat al iluminarii punct.

Folosirea surselor de lumina este un proces usor in Unity,se creaza sursa dorita si se aseaza unde se doreste in scena.

O sursa directionala reprezinta de obicei un soare si are un rol important in viziunea scenei.Directia luminii trebuie sa fie putin inclinata in jos .

Sursele de lumina punct si spot reprezinta,de obicei, surse artificiale de lumina de aceea pozitionarea acestora este determinata de obiectele aflate in scena.

Culoarea si intensitatea

Aceste doua proprietati pot fi editate din inspector.Desi valoarea acestora este predefinita pentru iluminat normal ,modificari specifice sunt necesare pentru crearea unei umbre pe obiect dorite precum si pentru a produce efecte speciale.

Iluminari imaginare( Cookies)

Deseori sunt folosite lumini care creaza impresia unui obiect care defapt nu exista .( umbra unui copac inexistest etc).Aceste efecte sunt foarte atmosferice dar crearea umbrelor se face simplu prin plasarea unei masti in fata unei surse te lumie te lumina.Uniti permite folosirea acestor elemente sub forma de texturi.

Umbrele

Luminile din Unite pot crea umbre ale unui obiect pe parti ale acestuia sau pe alte obiecte din apropiere.Aceste umbre adauga un grad de realism unei scene deoarece scot in evitenta marimea si pozitia obiectelor care ,in caz contrar ,ar arata „plate”.

Cand lumina trece in linie dreapta de la sursa va lovi la un moment dat un obiect din scena.Odata lovit ,lumina nu mai poate trece mai departe. Umbrele sunt create de obiecte in zonele in care lumina nu poate ajunge.

Umbrele pot fi activate din inspector.Umbrele aspre sunt umbre cu margini ascutite.Acestea sunt mai putin realistice dar au cerinte mult mai mici decat cele fine.

Umbrele sunt determinate in partea finala de rendering.Cand scena este creata dupa imaginea vazuta de camera,fiecare pozitie de pixel in vizor este transformata intr-un sistem de cordonate de lumina.

Iluminarea globala
Acest sistem modeleaza modul in care lumina este respinsa de pe unele suprafete pe altele( lumina indirecta) fara a fi limitata la doar lumina ce loveste suprafata direct de la o sursa de lumina.

Modelarea luminii indirecte permite crearea efectelor ce fac o lume virtuala sa para mai realistica si conectata intrucat obiectele isi afecteza aparentele reciproc.

Un exemplu este efectul numit „sangerare de culoare” in care daca lumina loveste un obiect rosu, culoarea acestuia va „sari” pe peretele de langa acel obiect.

Deoarece calculele necesare pentru acest tip de iluminare sunt prea incete ,acesta se foloseste doar in situatie care nu sunt in timp real(filme CG etc)

Limitarea acestui model de iluminare este faptul ca obiectele in miscare nu pot transmite lumina catre alte obiecte sau invers,doar pot primi lumina de la alte obiecte statice folosind „light probes”.

Controlul parametrilor de iluminare globala se face prin „Lighting window” unde se pot modifica proprietati precum si optimizarea calitatii,vitezei si spatiului de stocare necesar.

Camera

La fel cum camerele sunt folosite in filme pentru a relata poveste audientei,in Unity camerele au rolul de a arata jucatorului lumea jocului.

Tot timpul exista cel putin o camera in scena,dar se pot adauga mai multe.Un numar mai mare de camere permit crearea unui joc cu doi jucatori in timp real prin modul splitscreen.

Camerele pot fi animate sau controlat prin fizica.Practic orice este posibil cu camerele si se pot crea scene pentru orice stil de joc.

O scena in Unity este creata prin miscare si aranjare de obiecte in spatiu 3D. Deoarece ecranu vizualizatorului este in doua dimensiuni este nevoie de o metoda de captare si transformare in „plat” a imaginii pentru ecran.Acest lucru se face folosind camere.

O camera este un obiect ce defineste o vedere in spatiul scenei. Pozitia obiectelor defineste punctul de vedere, in timp ce axele de inainte si sus ale obiectului definesc directia de vizioinare precum si partea de sus a ecranului.

Componenta camerei mai defineste si marimea si forma regiunii care intra in viziualizare.Cu acestea,camera poate afisa pe ecran ce „vede” . Pe masura ce camera se misca si se roteste,imagina transmisa de aceasta se va misca si rotii corespunzator.

Camera in lumea reala sau chiar ochiul uman, vede lumea in asa fel incat obiectele par mai mici la distante mai mari fata de punctul de vedere.Acest efect se numeste perspectiva si este folosit pe scara larga in arta sau in grafica asistata de calculator si este un factor important pentru crearea unei scene realistice.

Unity suporta camere cu perspectiva,dar nu tot timpul este necesara mai ales pentru o scena in care nu se doreste efecte vizuale.O camera care nu reduce marimea obiectelor cu distanta se numeste camera ortografica si este disponibila in Unity.

Ambele tipuri de camere au o limita la distanta care o pot reda din pozitia curenta.Limita este definita de un plan care este perpendicular cu directia in fata a camerei.Acest lucru este denumit ca plan departare taiat fiindca obiectele aflate la o distanta mai mare de camera sunt „taiate” (excluse din randat). Exista si inversul acestui efect numit plan apropiere taiat in care obiectele care sunt prea aproape de camera sa dispara din vederea acesteia.

Fara perspectiva,obiectele par de aceasi dimensiune indiferent de distanta la care se afla acestea.Acest lucru inseamna ca volumul de vizualizare a unei camere ortografice este definit de o cutie dreptunghiulara ce se extinde intre doua planuri taiate.

Cand este folosita perspectiva,obiectele se miscoreaza cu distanta.Acest lucru inseamna ca latimea si inaltimea partii vizibile creste cu distanta.

Pentru scene interioare camera poate sa fie aflata complet in interiorul obiectelor reprezentand interiorul unei cladire, a unei pesteri sau a unei alte structuri.

Cand actiunea se petrece in exterior vor fi multe zone goale intre obiecte care nu sunt umplute cu nimic.Aceste zone de fundal sunt reprezentate de obice de spatiu,cer sau adancurile unei scene subacvatice.

O camera nu poate lasa fundalul complet indecis si trebuia sa il completeze cu ceva . Cel mai user este sa coloreze fundalul cu o culoare simpla inainte de a randa o scena peste acesta.

Un mod de fundal este Skybox, care este o „cutie” tapetata cu imagini ale cerului.Camera este plasata in centrul cutiei si cerul se va vedea din toate directile.Camera vede zone diferite cand se roteste dar nu se misca niciodata din centru.Cutia este randata in spatele obiectelor scenei si reprezinta o vizualizare pe o distanta infinita.

De obicei ,o camera arata intregul ecran deci doar o singura camera poate fi activa la un moment dat.Oprind o camera si pornind alta printr-un script se poate transfera de la o camera la alta,creeand astfel un efect mai cinematic

var firstPersonCamera: Camera;

var overheadCamera: Camera;

function ShowOverheadView() {

firstPersonCamera.enabled = false;

overheadCamera.enabled = true;

}

function ShowFirstPersonView() {

firstPersonCamera.enabled = true;

overheadCamera.enabled = false;

}

Occlusion Culling este trasatura ce opreste randarea obiectelor cand acestea nu sunt vazute de camera fiind ascunse de alte obiecte.Acest lucru nu se face automat deoarece de cele mai multe ori obiectele aflata la cea mai mare distanta de camera sunt desenate primele si obiectele mai apropiate sunt desenate asupra acestora.

Aceasta metoda este diferita de Frustum Culling,deoarece opreste si randarea obiecteleor aflate in afara vederii camerei precum si obiectele aflate dupa altele.

Vizualizare fara Occlusion Culling

Toate elementele scenei sunt randate.

Vizualizre cu Occlusion Culling

Doar elementele aflate in vederea camerei sunt randate

Procesul acesta se desfasoare folosind o camera virtuala care umbla prin scena si creeaza o ierarhie cu obiectele vizibile.Datele acestea sunt folosite apoi de fiecare camera pentru a indentifica ce este vizibul si ce nu este vazut .Echipat cu aceste infromatii Unity asigura ca doar elementele vizibile sunt randate.Acest lucru reduce numarul de apeluri de desenat si sporirea performantei jocului.

Shadere

Toata randarea in Unity este facuta cu shadere care sunt scripturi mici care permit configurarea modului cum hardwareul grafic este setat pentru randare

Materiale

Exista o relatie stransa intre materiale si shadere in Unity.Shaderele contin cod ce defineste ce tip de proprietati si burnuri se vor folosi.Materialele permit ajustarea proprietatilor si desemnarea bunurilor.

Odata ce materialul este creat,acesta poate fi aplicat oricariu obiect apoi se pot modifica proprietatile prin inspector.

Se poate selecte care shader dorim sa folosim la un material.Acest lucru se face tot din inspector. Proprietatile pot fi culori,slidere,texturi etc.Daca materialul este aplicat unui obiect activ in scena ,schimbarea se va observa in timp real.

Exista un set de 8 shadere native in editorul Unity.Cele principale sunt folosite pentru texturarea obiectelor.Acestea sunt :

-Normal: pentru obiecte texturate opac.

-Transparen: pentru obiecte partiari transparente(texturile definesc gradul de transparenta)

-TransparentCutOut: pentru obiecte care au parti total opace sau transparente.

-Self-Illuminated: pentru obiecte care au parti ce eimit lumina

-Reflective: pentru obiecte texturate opac ce reflecta mediul inconjurator.

Pe langa catergoriile principale de shadere ,se mai gasesc si alte categorii pentru obiective specializate:

-FX: pentru efecte de iluminat sau apa;

-GUI: pentru afisarea interfetei grafice;

-Nature: pentru copaci si sol;

-Particles: sistem de efecte de particule;

-Render FX: shadere pentru „skybox”;

-Toon: shadere pentru randare tip desen-animat.

Un shader practic defineste o forumla pentru modul in care arata un joc.

Intr-un singur shader exista un numar ridicat de proprietati(de obicei texturi).Shaderele sunt implementate prim materiale,care sunt atasate direct obiectelor aflate in proiect.

In material se alege shaderul dupa care se definesc proprietatile acestuia.

In mare parte ,shaderul defineste metoda de randare a unui obiect ,orice fragment folosit precum si unele proprietati ale texturilor sau culorilor

Materialele definesc ce texturi se vor folosi pentru randare ,precum si ce culori.

Shaderele sunt create de programatori grafici,prin intermediul limbii de programare ShaderLab.

Desi limbajul este simplu ,implementarea shaderului pentru a lucra bine cu o varietate de placi video necesita cunostinte ridicate legate de modul de lucru al placilor video.

Shader "shader" {

Properties {

_Texture ("textura", 2D) = "alb" { }

// aici se adauga proprietati cum ar fi culoare

}

SubShader {

// acest loc consituie „corpul” codului de shader

}

SubShader {

// aici se poate scrie un cod mai simplificat pentru a putea rula pe placi video mai vechi

}

}

Unity dispune de un nou tip de shader nativ numit Shader Standard.Acesta este creat pentru a inlocui o mare parte din shaderele vechi ,majoritatea fiind folosite pentru a randa obiecte realistice cum ar fi piatra ,lemn ,sticla ,plastic ,metal etc.

Acest shader este selectat ca implicit cand este creat un nou material,acesta fiind compatibil cu toate combinatile de caracteristici (bump,transparent,reflectiv etc).

Tipul acesta de shader mai incorporeaza si un modul de iluminat mai avansat numit Umbrire bazata pe fizica(Physically Based Shading sau PBS).

PBS simuleaza interactiunea dintre materiale si lumina intr-un mod ce mimeaza realitatea.Acest mod a devenit posibil recent.Este folosit cel mai eficient in situatii in care iluminatul si materialele trebuie sa colaboreze intuitiv si realistic.

Ideea in spatele acestui shader este crearea unei cai eficiente si usoare de creare a unei atmosfere consistente si plauzibile in diferite conditii de iluminat.

Se modeleaza dupa cum se comporta lumina in realitate ,fara a folosi ale tipuri de modele care pot sau nu sa dea rezultate favorabile.

Pentru a face asta se folosesc principii ale fizicii,incluzand conservarea energiei(obiectul nu reflecta mai multa lumina decat primeste),reflectii Fresnel si cum se ascund suprafetele unele de altele.

Shaderul Standard este creat cu gandul la suprafete tari si se poate ocupa cu majoritatea materialelor din lumea reala cum sunt pietrele sau sticla etc.Poate face treba buna si cu materiale mai moi cum sunt pielea si textilele.

PBS este foarte accesibil pentru utilizatorii Unity prin shaderul acesta,el fiind integrat implicit si se poate activa prin inspector.

Editorul de materiale este un modul in inspectro ce permite modificarea parametrilor materialului.

La o singura vizionare se pot vedea ce caracteristici sunt prezente si se poate vedea materialul.

Texturile materialelor sunt generate in unul sau mai multe moduri,se pot crea intr-un editor 2D de imagini cum est Adobe Photoshop sau pot fi randate dintr-un pachet 3D unde se pot genera modele de rezulutie inalta.

De obicei texturile nu contin lumini.Un dezavantaj PBS este ca obiectele reactioneaza la lumina cum ne asteptam ,ceea ce face ca folosirea lui la unele texturi ce contin infromatii legate de iluminat.

Inainte de introducerea PBS ,Unity avea mai mult de 80 de shadere native ce erau folosite pentru diferite obiective.Acestea sunt inca incluse in program dar este recomandata folosirea Shaderului Standard in cat mai multe locuri.

Majoritatea shaderelor vechi au fost inlocuite si din pricina performantei care a crescut considerabil cu introducerea PBS

Performanta este afectata de doua lucruri: shaderul propriu-zis si calea de randare care este folosita de camera.

Pe langa shaderele complexe Unity mai dispune si de unele simplificate dedicate platformei mobile sub catergoria Mobile.Acestea functioneaza si pe celelalte platforme dace se trece cu vederea peste simplitatea acestora.

Motorul Teren

Sistemul teren din Unity permite adaugarea ,de catre utilizator,a unor peisaje extinse jocurilor.

In timpul executiei,randarea terenului este foarte optimizata pentru eficienta in editor.O selectie de unelte este disponibila pentru a crea terenuri usor si rapid.

Terenul se adauga ca obiect,desi la inceput acesta este un plan larg si plat.Proprietatile acestuia se afla in inspector.Aici gasim si unelte pentru a crea orice peisaj dorit de utilizator.

Cu exceptia amplasarii copacilor si setarile implicite,toate toate uneltele asigura un set de „pensule” si setari pentru marime si opacitatea acestora.Nu este o coincidenta faptul ca acestea se aseamana cu uneltele de pictura ale unui editor de imagini deoarece detaliul terenului este creat in exact acelasi mod,prin „pictarea” in peisaj.

Cu unealta de ridicat/coborat teren putem modifica gradual inaltimea terenului cu ajutorul pozitiei mouseului.

Pe teren se pot adauga imagini pe post de textura pentru a crea culoare sau detalii fine.

Intrucat terenurile reprezinta obiecte mari,este necesar sa se foloseasca texturi care se repeta perfect pentru ca aceasta sa nu fie sesizabila de catre personajele care sunt in apropierea solului.

O textura va servi ca fundalul peisajului peste care se pot adauga alte zone de textura ca sa putem simula diferite suprafete ale pamantului cum ar fi iarba,desert si zapada.Transparenta acestora poate fi variabila pentru a crea o tranzitie graduala intre diferitele tipuri de texturi,de la iarba la nisip etc.

Majoritatea peisajelor necesita vegetatie,de aceea Unity dispune de un mod usor de adaugare de copaci. Grupuri de copaci pot fi „pictati” pe teren similar ca si texturile ,dar acestia sunt obiecte 3D care cresc de la suprafata.Motorul grafic folosesti optimizari pentru a mentine performante bune chiar daca cream paduri dense care contin mii de copaci.

Unealta de adaugare de copaci este dispusa de un slider pentru marime precum si slidere specifice.

Se pot selecta inaltimea maxima a copacilor precum si densitatea acestora.Latimea copacilor este proportionala cu inaltimea acestora pentru a nu strica uniformitatea.

Tot aici gasim si controlul de variatie a culori sau al rotatiei copacului.Aceste unelte sunt folosite pentru crearea unei impresii de viziune naturala a padurii fiind lipsita de copaci identici.

Unity contine si un creator de copaci in care utilizatorul poate sa isi creeze copaci proprii care vor fi folositi in scene specializate.

Copacii creati in scena sunt interactivi cu anumite efecte,ceea ce adauga inca un nivel realismului(exemplu miscarea copacilor sau a frunzelor la adierea vantului).

Iarba si alte obiecte mici cum sunt pietrele sunt randate cu ajutorul imaginilor 2d care reprezinta grupui individuale iar alte detalii sunt generate de catre motor.

Pentru a usura munca ,unelte speciale sunt disponibile pentru a crea iarba precum si a modifica proprietatile acesteia( textura,latimea,densitatea etc.)

Exista si un mod Billboard care face ca imaginea ierbii sa se roteasca tot timpul pentru a fi fata in fata cu camera.

Obiectele mici cum sunt pietrele sau alte detalii minuscule se produc in acelasi mod dar cu o alta unealta.

Pentru un plus de realism se pot crea zone de vant unde obiectele pot interactiona cu acesta.

Prin aceasta metoda se pot crea miscari realiste ale copacilor si a ierbii creand o scena mai naturala.

Unealta este simplista dar permite modificarea principalelor caracteristici cum sunt directia,viteza sau frecventa.

Sistemul de particule

Intr-un joc 3D majoritatea caracterelor si elementele de scena sunt reprezentate ca modele,in timp ce un joc 2D foloseste „sprite” pentru aceste scopuri.Totusi intr-un joc exista si alte entitati care sunt fluide si intangible in natura ceea ce face crearea lor mai complicata folosint doar modele si spriteuri.Pentru efecte cum ar fi lichide ,fum,nori,foc etc. o diferita abordare este necesara,aceasta fiind sistemul de particule.Acesta poate captura fluiditatea si energia obiectului dorit.

Particulele sunt imagini mici si simple care sunt afisate si miscate in numar mare de un sistem de particule.Fiecare particula reprezinta o portiune mica a unui fluid sau a unei entitati amorfe si efectul tuturor particulelor creaza,impreuna, impresia unei entitati coplete.

Un exemplu ar fi un nor de fum,acesta fiind creat din texturi mici ce se aseamana cu un nor.Cand acestea sunt aranjate impreuna efectul creata este de un nor mai mare si voluminos.

Dinamica acestui sistem este controlata de utilizator.

Fiecare particula are o durata de viata predeterminata,de obicei de cateva sencunde,timp in care se poate supune anumitor schimbari.

Viata ei incepe cand este generata sau emisa de sistemul sau de particule.Acesta emite particule aleatoriu intr-o regiune selectata sub forma diferita(sfera,con,cub etc.).Particula este afisata pan cand timpul sa scurs,timp in care aceasta dispare din sistem.

Rata de emisia a sistemului indica aproximativ cate particule sunt emise pe secunda.

Fiecare particula are atasat un vector de viteza care determina distanta si directia pe care o ia aceasta.

Aceste proprietati pot fi modificate de forte externe.Pe intreaga durata a vietii,particula mai poate sa isi schimbe rotatia ,culoare si marimea.

Pentru a simula diferite fluide este necesara o combinatia de particule.

Sonde de refletie

Deseori in filme CG si animatii se folosesc reflectii realistice,care dau un simt de „conectivitate” intre obiectele aflate in scena.Insa precizia acestor reflexii vine cu un cost ridicat in procesare iar acest lucru limiteaza sever folosirea lor in timp real in jocuri.

Pentru a contracara acest dezavantaj ,jocurile folosesc o tehnica numita „reflection mapping” pentru a simula reflectile obiectelor dar tinand performanta jocului in limitele acceptabile.

Aceasta tehnica presupune ca toate obiectele reflective din scena „vad” aceleasi imprejurimi.

Mediul vizual pentru un punct in scena poate fi reprezentat de un cub.

Aceasta este conceptual ca o cutie cu imagini de la vizualizarea din 6 directii(sus,jos,stanga,dreapta,fata,spate)

Pentru ca un obiect sa prezinte reflectii,shaderul sau trebuie sa aibe acces la imaginile ce reprezinta cubul.Fiecare punc din suprafata obiectului „vede” o portiune mica din cup in directia in suprafetei.

Shaderul foloseste culoarea cubului si calculeaza ce culoare va avea suprafata obiectului.

Exista mai multe tipuri de sonde de reflectii:

-Baked: foloseste reflectii generate in editor

-Realtime: creaza reflectii in timpul executie in interiorul jucatorului nu in editor.

Ca orice efect realistic,reflectile necesita putere de calclul mare.Cu cat rezolutia acesteia este mai mare cu atat va creste timpul de randare.Reducand rezolutia in zone unde detaliul nu este asa de important va optimiza performanta scenei.

Se mai poate selecta si modul de reimprospatare care ca putea fi redus in asa fel incat sa nu se piarda din detaliu si performantele sa fie acceptabile.

Editorul de sprite

Acest editor este unul dintre cele mai importante unelte folosite in jocurile 2D precum si pentru efectele de particule 2D.

Desi unele sprite contin un singur element grafic,de cele mai multe ori se compina un numar mai mare de elemente intr-o singura imagine.

Cel mai direct mod de a folosi editorul este de a intentifica elementele manual.Cand selectam o imagine ,editorul ne va afisa zona selectiei precum si ce parametrii pot fi modificati.

Se pot adauga alte elemente si se pot manipula dupa dorinta.Tot de aici se pot si modifica anumite proprietati cum sunt latimea si inaltimea elementelor selectate fara a modifica restul imaginilor din compozitia sprite.

Cand se lucreaza cu grafica sprite ,este recomandat sa se foloseasca cu texturi separate pentru fiecare caracter.Totusi o portiune semnificativa dintr-o textura sprite va fi deseori ocupata de spatiul gol dintre elementele grafice iar acest lucru duce la pierdere din memoria video in timpul executiei.
Pentru a combate acest lucru este recomandat sa se impacheteze graficele de la diferite texturi sprite intr-una singura sub numele de „atlas”.

Unity genereaza aceste texturi separat in spatele editorului pentru ca utilizatorul sa nu trebuiasca sa intervina reducand cantitatea de lucru pentru un proiect.

Toate acestea sunt facute cu modului numit „Sprite Packer” care este integrat in Unity.

Interval dinamic ridicat(HDR)

In randarea standard, valorile rosu,verde si albastru ale unui pixel sunt reprezentate de o fractie in intervalul 0..1, unde 0 reprezinta intensitatea minima iar 1 reprezinta intensitatea maxita pentru afisare.Desi acest lucru este simplu ,nu reflecta realistic si precis modul cum lucraza lumina in realitate.Ochiul uman tinde sa se ajusteze la iluminatul local,deci un obiect alb poate arata mai putin luminat intr-o incapare mai intunecate decat un obiect gri in lumina zilei.

Pe langa acestea ochiul uman este mai sensibil la diferentele de lumina la gama joasa decat la cea mai se sus.

Efecte visuale mai convingatoare se pot reproduce permitant randarii sa foloseasca intervale mai precise de reflectare a luminii ,precum in lumea reala.

Permitant folosirea valorilor aflata in afara intervalului 0..1 se numeste HDR.

Acesta este activat pentru fiecare separat prin componenta sa.

Cand este activ,scena este randata intr-o tampon de imagine HDR care acomodeaza valori ale pixelilor din afara intervalului 0..1.

Acest tampon este apoi postprocesat folosint efecte de imagine cum este „HDR bloom”.

Desi folosirea de HDR permite control mai complex al procesului luminozitatii, efectul de bloom are defectul de a reduce din precizia zonelor din compozitia scenei daca intensitatea pixelului este sub 1.0.Folosind HDR este posibil sa se aplice efectul de bloom doar pe anumite zone.Acest lucru duce la crearea unei scene mult mai placute ca aspect.

Avantaje HDR

-culorile nu se pierd in zone de intensitate mare

-efect bloom mai bun

-reducerea de efectului de „benzi” in zone de iluminat de frecventa joasa.

Dezavantaje HDR

-randarea este mai inceata si foloseste mai multa memorie video

-nu este suportat mod „anti-aliasing”

-nu este suportat de orice placa video.

Nivelul de detaliu

Cand un obiect dintr-o scena este aflat la distanta mare de camera ,cantitatea de detaliu care este vizibila este redusa foarte mult.

Totusi,acelasi numa de triunghiuri va fi folosit la randarea acestui obiect chiar daca detaliul nu este vazut.
O metoda de optimizare a acestui lucru se numeste Nivel de detaliu(LOD) care permite reducerea numarului de triunghiuri randate pe masura ce distanta de la camera creste.

Atata timp cat obiectul nu este aproape de camera ,LOD va reduce din stresul pus pe hardware si va spori performanta si timpii executiei.

In Unity se foloseste componenta LOD pentru randare a unui obiect.Motorul permite utilizatorului selectarea dorita a valorii LOD pentru obiecte precum si favorizarea valorilor mari sau a celor mici de LOD la diferite distante.

Copatibilitatea DirectX 11

Unity are abilitatea de a se folosi de APIul DirectX 11 care aduce multe instrumente de grafica avansate cum sunt shaderele de calcul, shadere „tesselalation”, modelul 5.0 de shadere etc.

Pentru a activa DirectX 11 in constructia jocului si a editorului se seteaza folosirea lui din setarile acestuia.Aceasta optiune este pornita implicit la orice proiect.

De tinut minte este faptul ca DirectX 11 necesita un sistem de operare compatibil(Windows 7,8 etc)

precum si un accelerator grafic cu nivel compativil(DX10,DX11).

Unity va notifica sub ce mod functioneaza prin tagul DX11 aflat la sfarsitul titlului.

Shaderele de calcul permit folosirea GPU ca un procesor paralel.Programele acestea sunt rulate pe placa video in afara randarii normale.Pot fi folosite pentru algoritmi masivi de tip GPGPU sau sa accelereza randarea jocului.

Pentru folosirea eficienta este recomandat un grad de cunostinta in arhitectura GPU precum si a algoritmilor paraleli.

#pragma kernel FillWithRed

RWTexture2D<float4> res;

[numthreads(1,1,1)]

void FillWithRed (uint3 dtid : SV_DispatchThreadID)

{

res[dtid.xy] = float4(1,0,0,1);

}

Shaderele de suprafata acum suporta efect tessellation simplu precum si dislocare.

Efectul tessellation ,simplificat, este impartirea unui polygon in mai multe parti.De exemplu daca se taie pe diagonala un patrat,acesta se transforma in doua triunghiuri.Acest lucru ,singur, nu imbunatateste realismul unui joc deoarece nu conteaza daca un patrat este randat ca doua triunghiuri sau ca doua mii de triunghiuri,tesselation creste semnificativ realismul cand cele doua triunghiuri sunt folosite la surse noi de informatie

Informatia luata de la acestea este transformata in informatie de inaltime,ceea ce permite polygoanelor de pe suprafata unei texturi sa fie ridicate sau coborate dupa informatia primita.

Acest lucru creste realismul exponential dar vine cu un dezavantaj,care in ultimii ani a fost redus considerbil.Problema cea mai mare a acestui efect este necesitatea de placa video suportata si relativ performanta.In ultimul timp pana si placile video de performanta medie suporta aceasta caracteristica.
Desi efectul poate fi folosit in tot mai multe acceleratoare grafice,problema performantei inca ramane,acesta inca necesita hardware capabil pentru calcului informatiei pentru fiecare model.

Optimizarea performantei

Performanta buna in jocuri este critica pentru succesul acestora.

Partea grafica a jocului „costa” sistemul in doua parti,partea GPU si partea CPU.Prima regula a optimizarii este gasirea problemei si locul acesteia,deoarece strategia din spatele optimizarii pentru GPU sau CPU este diferita,chiar opusa.

GPU este deseori limitat de latimea de banda a memoriei.

CPU este limitat de numarul de pachete ce trebuie randate.

Acestea sunt problemele des intalnite dar problema poate fi si altundeva,de exemplu scriptul sau fizica prezinta probleme

Optimizarea CPU

Pentru a randa un obiect pe ecran ,CPU trebuie sa verifice ce lumini afecteaza obiectul,sa seteze parametrii shaderului precum si sa trimita comenzi driverului grafic.Toate acestea pun stres pe procesor deci daca scena are multe obiecte acest lucru devine vizibil.

Un exemplu al fi, daca avem o mie de triunghiuri ,va fi mult mai „ifetin” pentru CPU sa proceseze acestea intr-un singur element decat in o mie de elemente separat.

Pentru a reduce cantitatea de lucru a procesorului se reduce numarul de obiecte vizibile prin:

-combinarea obiectelor apropiate

-reducerea numarului de materiale ale obiectelor prin imbinarea texturilor intr-un atlas

-folosirea mai redusa a elementelor care fac obiectele sa fie randate de mai multe ori( reflectii,umbre etc)

Optimizarea GPU

Pentru a optimiza geometria unui model se urmareste doua reguli simple:

-a nu se folosi mai multe triunghiuri de cat necesar

-folosirea unui numar mai mic de texturi UV.

De obicei numarul de poligoane ce trebuie procesat de hardwareul grafic nu este la fel cu cel raportat de aplicatia 3D.

Iluminatul ce nu este calculat este tot timpul cel mai rapid mod,de aceea se foloseste iluminatul static decat cel calculat in fiecare cadru.De obicei acest lucru durea mai mult deoarece ,procesul de generare a acestor elemente este mai lung dar,performantele cresc considerabil, iar vizual arata similar cu celalalt tip de iluminat.

Folosirea texturilor compresate este inca un mod de optimizare grafica.Acest lucru reduce marimea texturilor ceea ce imbunatate timpul de incarcare si reduce memoria video necesara si mareste drapatic performanta de randare.

In unele jocuri ,este esential sa fie taiate obiectele mai mici mai agresiv decat cele mai mari.De exemplu pietre mici sau ramasite pot fi facute invizibile la distante mari fata de cladiri inalte care inca ar fi vizibile.

Acest lucru se faci fie prin sistemul LOD sau prin selectarea manuala a distantei de taiere din camera.

Diferentele dintre un GPU de pe un PC de top si un GPU de pe un smartphone pot fi de ordinul sutelor,din punct de vedere al performantei.Acest lucru poate fi spus si despre GPU dedicate si cele integrate.

Pentru a combate aceste „goluri” se folosesc efecte mai simpliste care sunt mult mai rapide,cu un cost de realsim.Acestea se afla in categoria mobile.

Numarul de poligoane folosit depinde de calitatea dorita si de platforma tinta.

Pentru platforma mobila intre 300 si 1500 de poligoane sunt suficiente iar pentru PC intre intervalul 1500 si 4000.Se pot reduce aceste intervale daca jocul foloseste multe caractere in acelasi timp

II.3. Fizica

Corp rigid

Pentru a avea un comportament fizic convingator,un obiect din joc trebuia sa accelereze corect si sa fie afectat de coliziuni,gravitatie si alte forte.

Motorul de fizica inclus in Unity asiguracomponente care se ocupa de simularea fizicii.

Cu doar cativa parametri,se pot crea obiecte ce se comporta pasiv intr-un mod realistic(vor fimiscate de coliziuni sau caderi dar nu se misca singure).Controland fizica din scripturi ,se poate da unui obiect,dinamica de vechil sau chiar o bucata de obiect textil.

Uniti dispune de doua motoare de fizica separate,unuil pentru fizica 3D altul pentru cea 2D.

Conceptul din spatele acestora este identic (cel 3D are inca o dimensiune) dar sunt implementate cu componente diferite.

Principala componenta ce permite fizica unui obiect este corpul rigid sau RigidBodies.Cand un corp este atasat unui obiect acesta va raspunde imediat la gravitatie.Daca se mai adauga o componenta de coliziune acest obiect va fi miscat de coliziuni.

Fiindca o componenta de corp preia miscarile obiectului atasat ,aesta nu trebuie miscat din script.

Sunt cazuri in care nu se doreste ca obiectul sa aibe fizica controloata de motorul de fizica.

Acest caz se numeste kinematic unde componenta de corp este scoasa din controlul motorului si se poate edita din scripturi.

Cand un obiect se misca la o viteza lineara sau rotationala mai mica decat cea minima acesta va primi insusirea de „dormire”.Aceasta optimizare inseamna ca procesorul nu va pierde timp actualizand corpul pana cand este „trezit” (cand este pus in miscare). Pentru majoritatea scopurilor , tranzitia aceasta se face transparent.

Componenta de coliziune

O alta componenta a fizicii este cea de coliziune care defineste forma obiectului cu spocul de coliziune fizica. O coliziune ,care este invizibila, nu trebuie sa fie de aceeasi marime ca si obiectul la care este atasata.Cele mai simple coliziuni sunt cele primitive.

In 3D avem coliziune de timp sfera,cutie si capsula.In 2D se pot folosi coliziuni de tip cutie 2D precum si coliziune cerc 2D.

Orice numar din acestea poate fi adaugat pentru a crea coliziuni compuse.Cu o pozitionare atenta acestea pot aproxima forma obiectelor foarte precis ,mentinand performanta ridicata.

Componenta de coliziune poate fi adaugata unui obiect faca corp rigid ,pentru a crea podele,ziduri sau alte elemente ale scenei care nu au miscare.Acestea se numesc componente statice .

Fizica materialelor este o componenta importanta deoarece suprafetele trebuie sa simuleze proprietatile materialelor ce reprezinta.Un exemplu este o fasie de gheata trebuie sa fie alunecoasa in timp ce o minge ce cauciuc trebuie sa ofere o cantitate mai mare de frecare si sa sara la contactul cu solul.Desi forma coliziunii nu este deformata in timpul unei actiuni de coliziune, parametrii de frecare si saltare pot fi configrati folosind fizica materialelor.

Un sistem de scriptare poate detecta cand se produc coliziuni sau cand o coliziune intra in spatiul celeilalte fara a crea un efect de coliziune.Acestea sunt configurate ca declansatoare si nu se comporta ca un obiect solid si va lasa coliziunile sa treaca prin acesta.

Cand se produce o coliziune,motorul de fizica face apel la functii specifice unui script atasat obiectului implicat in coliziune.Acest cod se poate plasa ca orice alta functie sa raspunda unui eveniment de coliziune.De exemplu,se poate activa un sunet de lovire cand o masina loveste un obstacol.

Coliziunea statica este un obiect care nu are corp rigid dar are componenta de coliziune.

Acestea sunt folosite pentru geometria unui nivel care tot timpul va sta in acelasi loc si nu se va misca.Obiectele cu corp rigid ce interactioneaza cu aceasta vor avea coliziune dar nu va misca obiectul.

Motorul de fizica presupune ca efectele statice nu se vor misca sau schimba si poate faci optimizari bazate pe aceasta presupunere.In consecinta mutarea si schimbarea acestora in timpul rularii nu este indicata.

Coliziunea corp rigid este o componenta de fizica atasata unui obiect si simuleaza fizica ,fie aplicata de coliziuni fie aplicata de un script.Obiectele cu aceasta componenta poti interactiona cu alte obiecte si este folosit pentru a jocuri ce folosesc fizica.

Componenta de imbinare

Un obiect se poate atasa altui obiect cu ajutorul unei componente de imbinare.In mod normal se doreste o imbinare pentru a permite ceva libertate de miscare a unui obiect.

Imbinarile au si anumite optiuni care pot activa efecte specifice.De exemplu dorim ca o imbinare sa se rupa cand forta aplicata depaseste o anumita limita.

Controlere de charactere

Un caracter intr-un joc din filmat din perspectiva persoanei intai sau a trei a va avea nevoie de cele mai multe ori de fizica bazata pe coliziuni pentru a nu cadea prin podea sau sa treaca prin ziduri.

De obice acceleratia si miscarea caracterelor nu va fi realistica din punct de vedere al fizicii,acestea pot accelera,frana sau schimba directii aproape instant fara a fi afectate de inertie.

In cazul fizicii 3D acest tip de comportament se creaza cu ajutorul cotrolerului de caractere.

Aceasta componenta da caracterului un element de coliziune simplu,in forma de capsula care este tot timpu in pozitie dreapta in sus.

Controlerul are functii speciale proprii care modifica viteza obiectului si directia acestuia dar spre deosebire de restul componentelor acesta nu are nevoie de un corp rigid iar efectele de intertie nu sunt realistice.

Un controler de caracter nu poate trece printr-o coliziune statica a unei scene,deci va urmari podeaua si va fi blocat de ziduri.Poate impinge intr-o parte obiectele cu corp rigid dar nu va fi accelerat de coliziunile cu care intra in contact.Acest lucru inseamna ca putem folosi coliziuni 3D pentru a crea scena in care controlerul va merge dar nu suntem limitati de comportamentul realistic de fizca al caracterului propriu-zis.

Controlerul acesta este folosit de obicei pentru jocuri in care jucatorul nu se foloseste de fizica de corp rigid.

In majoritatea jocurilor din perspectiva persoanei intai,controalele nu sunt realistice din punct de vedere fizic.Caracterele alearga cu viteze mult prea mari iar oprirea se face instant.Deoarece acest lucru este nerealiztic,folosirea corpurilor rigide pentru a crea acest comportament nu este practica.Solutia este simpla,folosirea de controlere de caracter specializate.Acestea se misca in directia care este dictata de catre un script.Controlerul va executa aceste miscari dar va fi constrans de coliziuni.Va urca pe scari sau va aluneca pe ziduri.

Controlerul nu va reactiona la forte de capul lui si nu va impinge automat corpuri rigide.

Acest lucru necesita scriptare.

Este necesar un reglaj fin al caracterului pentru ca acesta sa fie conform scenei.Se pot modifica inaltimea si raza caracterului pentru a corespunde cu modelul acestuia.Este recomandat sa se foloseasca o marime de 2 metri pentru a da o impresie de caracter uman.

Unity dispune si de motor fizic 2D ,la care diferentele sunt minore.Componentele de fizica intr-un mediu 2D,cum spune si denumirea, detin doar doua axe,X si Y.

II.4. Scriptarea

Scriptarea reprezenta un „ingredient esential” in toate jocurile.Chiar si cele mai simple jocuri au nevoie de scripturi pentru a raspunde semnalelor de intrare a utilizatorilor si pentru aranjearea evenimentele in asa fel ca ele sa reactioneze la timpul vrut.

Pe langa acestea ,scripturile pot fi folosite pentru a crea efecte grafice ,controlul comportamentului fizic al obiectelor sau chiar impltementarea inteligentei artificiale pentru caracterele unui joc.

Scriptarea necesita timp si efort pentru a fi invatata,dar este necesara pentru crearea unui sistem complex de comenzi sau actiuni.

Toata scriptarea se face in standardul Mono,dar se pot folosi si alte metode de scriptare folosind doar motorul Unity.

Comportamentul obiecteleor este controlat de componente care sunt atasate de acestea.Desi componentele native sunt versatile ,utilizatorul va fi nevoit la un moment dat sa treaca peste acestea pentru a crea un sistem unic si personal.

Unity permite crearea componentelor personale folosind scripturi.Acestea permit declansarea unor evenimente,modificarea proprietatilor componentei si raspunderea la apelurilor de comanda in orice mod dorit de utilizator.

Limbile de programare native sunt

-C#: un limbaj standard similar cu Java si C++;

-UnityScript: un limbaj creat special pentru folosire in Unity ,modelat dupa JavaScript.

using UnityEngine;

using System.Collections;

public class MainPlayer : MonoBehaviour {

// Zona aceasta este folosita pentru initializare

void Start () {

}

// Reimprospatarea este chemata doar o data pe cadru

void Update () {

}

}

Cand sunt create scripturile se creaza un nou tip de componenta care este atasata obiectelor ca oricare alta componenta.Acestea au proprietati care sunt modificabile prin inspector.

Acestea permite si editarea valorilor din interiorul scriptului.

In C# ,o variabila trebuie declarata ca publica pentru a fi vazuta de inspector.In UnityScript variabilele sunt din start publice pana nu se specifica altfel.

#pragma strict

private var invisibleVar: int;

function Start () {

}

Un avantaj major al motorului de scriptare Unity este faptul ca variabilele unui script poate fi manipulat in timpul rularii.Acest lucru este foarte folositor pentru a vedea direct si in timp real modificarile aduse ,fara nevoia de oprire si restartare a programului.

Dupa ce se termina rularea aceste variabile revin la setarile initiala pentru a nu se crea defecte.

Obiectele se pot controla prin intermediul scripturilor ,care pot schimba pozitia acestora sau chiar cularea materialului unui obiect.

Scripturile pot modifica in timp valorile unor obiecte sau elemente ale scenei in functie de comenzile utilizatorului.Prin schimbarea,crearea sau distrugerea obiectelor la timpul potrivit se pot crea elemente de joc de orice tip.

void Start () {

Rigidbody rb = GetComponent<Rigidbody>();

// Schimbarea masei unui corp rigid al unui obiect.

rb.mass = 10f;

}

Un script in Unity nu este ca un o idee traditionala a unui program ,unde codul functioneaza continuu intr-o bucla pana isi termina sarcina. Aici controlul revine scriptului intermitent prin apelul la anumite functii care sunt declarate in acesta.Odata ce aceasta functie a fost executata controlul revine inapoi la motorul Unity.

Aceste functii sunt numite functii eveniment deoarece sunt activate de Unity ca raspuns la evenimentele ce se petrec in timp real pe parcursul rularii.

Un joc este ca o animatie unde cadrele acesteia sunt generate pe loc.Un concept cheie este manipularea pozitiei ,statutul sau comportamentul obiectelor inainte de fiecare cadru randat.

Aceasta functie se numeste functie de reimprospatare .Aceasta este apelata inainte ca cadrul sa fie randat si inainte de calucularea animatilor

void Update() {

float distance = speed * Time.deltaTime * Input.GetAxis("Horizontal");

transform.Translate(Vector3.right * distance);

}

Motorul de fizica reimprospateaza discret in timp similar cu modul de randarea a cadrelor.

Un alt tip de eveniment este acela de interfata.Unity dispune de un sistem de randare pentru interfata grafica a utilizatorului(GUI) peste actiunea principala in scena si pentru raspundearea la comenzi.Acest tip de functie se numeste OnGUI.

void OnGUI() {

GUI.Label(labelRect, "Ai pierdut!");

}

Acest cod este folosit diferit de cel normal pentru ca acesta sa detecteze evenimentele create de comenzi care vin de la mouse sau de la tastatura asupra unui obiect din scena.

Un set de functii sunt prezente pentru a permite scriptului sa reactioneze cu actiunile mouseului.De exemplu cand un buton de la mouse este apasat in timp ce pointerul este deasupra unui obiect din scena.

Motorul de fizica reporteaza coliziunile asupra unui obiect prin apelul functilor eveniment aflate in scriptul obiectului.

void OnCollisionEnter(otherObj: Collision) {

if (otherObj.tag == "Glont") {

ApplyDamage(10);

}

}

Aceste functii pot fi apelate de mai multe ori succesiv in functie de contactul detectat asupra obiectelor.

Unele jocuri tin un numar constant de obiecte in scena,dar este deseori folosita stergerea sau crearea unor obiecte sau caractere in timpul rularii.

Un obiect poate fi creat folosind functia „instantiate” care poate crea o copie dupa un obiect existent.

public GameObject inamic;

void Start() {

for (int i = 0; i < 5; i++) {

Instantiate(inamic);

}

}

Aceasta copie nu trebuie sa fie prezenta in scena.Aceasta poate fi prezenta in ierarhie.

Pentru a distruge un obiect se poate folosi functia „destroy” care poate sterge un obiect dupa ce sa reimprospatat cadrul sau dupa un timp predefinit

void OnCollisionEnter(Collision otherObj) {

if (otherObj.gameObject.tag == "racheta") {

Destroy(gameObject,.5f);

}

}

Aceasta functie poate sa distruga componente ale obiectului fara a afecta obiectul propriu-zis.

Consola

Acest meniu afiseaza erorile,avertismentele precum si alte mesaje generate de Unity,pentru a ajuta la depanarea programului

Se pot sterge mesaje sau chiar modifica modul de afisarea a mesajelor .Acestea pot fi filtrate pentru a afisa doar erorile compilatorului sau doar alte mesaje dorite de utilizator

MonoDEVELOP

MonoDevelop este un mediu de dezvoltare integrat(IDE) care se gaseste in Unity.

Un IDE combina operatia familiara a unui editor de texte impreuna cu caracteristici de depanare si alte sarcini de management.

Mono permite editarea fisierelor de sursa ,acestea fiind deschise ca un fisier de tip text.

Acest mediu permite adaugarea unor puncte de pauza care opreste momentan executia scriptului cand ajunge la aceasta zona.

Dupa ce este „inghetata” linia de cod poate fi depanata apoi prin determinarea procesului acestei functii pas cu pas.

Informatii despre statutul executie se afla la baza editorului Mono cand acesta este in stadiul de „inghetata”.

Depanatorul MonoDevelop poate fi atasat unui device cu sistemul de operare Android folosind cablul USB .

II.5. Sunetul

Unity permite includerea de clipuri scurte,surse ,ascultatori precum si manipularea acestor parametrii.

Orice scena a unui joc este incompleta fara audio,fie sunete de funtal sau efecte sonore.

Sistemul audio inclus in Unity este flexibil si puternic,permitand importarea a majoritatii formatelor audio precum si efecte complexe (spatiu 3d ,ecou etc).

Sistemul permite si inregistrarea sunetelor de la orice sursa de intrara pe spatiul de stocare a masinii folosite de utilizator

In realitate sunetele sunt emise de obiecte si auzite de ascultatori.Modul cum este perceput un sunet depinde de anumiti factori.Un ascultator poate sa realizeze directia sunetului precum si distanta acestuia folosindu-se de calitate si intensitate.

Obiectele care se misca repede produc un sunet care isi schimba inaltimea in timp ce se misca.

Pentru a simula efectele de pozitie,este nevoie de sunete care au originea in surse audio atasate obiectelor.

Sunetul emis este perceput de un ascultator audio atasat altui obiect care,de obicei, este camera principala.Unity poate sa simuleze efectele de distanta ale sursei si pozitia de la ascultator si sa le ruleze catre utilizator in mod optim.

II.6. Animatia

Unity foloseste un sistem bogat si sofisticat de animatie numit Mecanim.

Acesta ofera:

-un spatiu de lucru si un mod de crearea a unei animatii pentru taote elementele unui proiect de la obiecte la caractere.

-suport pentru importarea clipurilor si a animatilor create

-posibilitatea de a copia animatii de la un caracter la altul

-managementul interactiunilor complexe dintre animatii.

-animarea diferitelor parti ale corpului pe diferite moduri .

-straturi si masti

Sistemu de animatie este bazat pe conceptu de clipuri,care contin infromatii despre modul cum unele obiecte trebuie sa isi schimbe pozitia ,rotatia sau alte proprietati pe parcursul unui timp dedicat.

Fiecare clip poate fi gandit ca o inregistrare lineara.Fiecare clip se poate importa din surse externe cum sunt Maya sau Max.

Clipurile sunt organizate intr-o structura numita controler animator.Acesta decide cand sunt rulate animatiile si cand trebuie imbinate sau schimbate.

Controleru animator are referinta la clipurile folosite si se ocupa de diferitele statuturi si tranzitii de animatie.

Optimizarea si performanta

In majoritatea cazurilor caracterele au nevoie de un numar mare de „oase” ,care construiesc „scheletul” de animatie.Acest lucru marestea dimensiunea programului iar performatele vor scadea proportional,procesorul fiind nevoie sa calculeze proprietatile fiecaruia.

Pentru a combate acest lucru se opresc animatiile oaselor care nu sunt folosite ,reducand considerabil costul procesului.Aceasta optimizare se poate mari in continuare daca se ascund atasamentele acestora

Animatorul nu proceseaza daca un controler nu este astasat acestuia.

Rularea unui clip fara amestecare poate sa reduca performantele.Mecanim creaza tampoane temporare care sunt folosite pentru aceasta.

Schema Mecanim este optimizata pentru animatie cu amestec precum si pentru amplasamente mai complexe

Pentru o optimizare mai adanca se folosesc si taieri ale animatorilor,prin dezactivarea animatiilor si modelelor care nu sunt vizibile .In acest mod animatile unor obiecte invizibile sau aflate la departare ,nu sunt actualizate marind performantele considerabil.

Capitolul III

Aplicatie creata in Unity

III.1. Conceptul

Aplicatia pe care am creat-o are la baza vizuala „pixel art” care este foarte des folosit in mediul digital . Pixel art sau grafica retro este un stil vizual placut care a aparut in anii 80 cand au aparut pe piata consolele de jocuri,de aceea aduce amintiri placute utilizatorilor care au fost initiaiti in aceste aparate inca de pe vremea cand au fost lansate.

Acest tip de grafica se realizeaza prin manipularea imaginii la nivel de pixel.Acest lucru nu inseamna ca utilizatorul deseneaza imaginea pixel cu pixel ci faptul ca el foloseste unelte care ii permit controlul individual al unui pixel.

Lucrand la nivelul de pixeli mi-a permis sa scot cat mai mult detaliu din imaginile create.

Pixel art a aparut in era cand calculatoarele nu erau la fel de puternice ca in zilele de azi ,iar lucrul cu grafica era limitat de rezolutie si culori.

Pentru a contracara aceasta limitare ,artistii au folosit tehnici cu care creau detaliu fara a avea nevoie de o paleta de culori mai mare.

O tehnica folosita se numeste „dithering” cu care artistul deseneaza o culoare peste pixeli de alta culoare in forma de carouri.Cand este micsorata ,imaginea creaza iluzia de imbinare a culorilor .

Acest lucru reduce numarul de culor necesar precum si crearea unei diversificari a detaliului fara a incarca fisierul cu multe informatii.

In pixel art ,culorile au un rol foarte important .Un pixel cu o culoare corecta poate schimba total imaginea .

Pentru un sprite de 16×16 pixeli , fiecare dintre acestia contribuie la o viziune mai buna a unui character.

Jocul se numeste Cyber Rush si l-am creat doar in spatiu 2D deoarece in viziunea mea se potriveste cel mai bine cu genul acesta de grafica. Pe langa experienta vizuala ,am vrut sa creez ceva care sa puna la incercare gandirea si reflexele jucatorilor fara a fi nevoit sa piarda timpul cu invatatul comenzilor si a setarilor specifice.

Acest tip de joc este accesibil tuturor indiferent de varsta. Modul de jucat este numit „side scrolling game” unde jucatorul trebuie sa sara peste obstacole pentru a ajunge cat mai departe si pentru a strange un scor cat mai mare.

Jocul a fost creat pentru platforma mobila pentru ca este un mediu flexibil si imi permite testarea usoara a aplicatiilor facute pe acesta.Industria platformei mobile a crescut exponential in ultimii ani,lucru care a dat naster multor unelte si metode de dezvoltare de aplicatii.

Acest lucru m-a determinat sa aleg aceasta platforma fata de altele care,desi aparute de mult timp

necesita un grad mai mare de timp depus precum si complexitate mai ridicata care nu o doream in acest joc.

In tema cu stilul jocului a fost si tipul de sunete ales.

Acestea sunt similare cu muzica pe 8-biti din aceeasi perioada care era creata de cipurile integrate fie intr-o consola(SNES) fie pe platforma portabila(Gameboy).

Alegand aceste tipuri de sunete ajuta la imersiunea jucatorului in lumea jocului ,fara a fi dereglat de diferenta de „complexitate” dintre elementele ce il compun.

III.2.Dezvoltarea

Ca orice program,conceptia acestuia incepe cu viziune in mare a acestuia si ideile temporare.

In sine,jocul este un tip numit „infinite runner” unde obiectivul jocului nu este terminarea acestuia sau trecerea de nivel ci doar strangearea unui numar cat mai mare de distanta parcursa.

Personajul controlat de utilizator este blocat la o anumita viteza iar directia este singulara pe axa X de la stanga la dreapta.

Am vrut sa creez un joc simplu si mic ca dimensiuni.Pentru aceasta am impartit jocul in trei parti de dezvoltare.

Prima parte este cea vizuala si auditiva.Fiind creat folosindu-ma de sistemul artistic „pixel art” am inceput sa creez decorul ,spatiu si caracterul in Photoshop,fiind foarte usor sa lucrez in acel mediu ,care , are o cantitate mare de unelte pentru a lucra la nivel de pixel.

Pentru imaginea de fundal am ales forme care arata ca niste cladiri mai futuriste .Acestea,impreuna cu un efect de miscare face ca personajul sa iasa in evidenta iar fundalul sa fie pe post de atmosfera si dinamica.Acest efect se numeste efect „parallax” si face ca obiectele aflate in apropierea camerei sa se miste mai repede decat dele din departare.Acest lucru se face prin scriptare

using UnityEngine;

using System.Collections.Generic;

public class LevelManager : MonoBehaviour

{

private float worldScrollSpeed = 7.0f;

private float totalDistance = 0.0f;

private SceneryLayer[] scenery;

public float TotalDistance

{

get { return totalDistance; }

}

void Start()

{

scenery = GetComponentsInChildren<SceneryLayer>();

}

public void Restart()

{

totalDistance = 0.0f;

foreach(SceneryLayer layer in scenery)

layer.Restart();

foreach(SceneryLayer layer in scenery)

{

if(!layer.isInfinite)

layer.DisableNextLayer();

}

}

void Update()

{

float speed = (GameManager.Game.IsPaused || GameManager.Game.IsGameOver) ? 0.0f : worldScrollSpeed;

totalDistance += speed * Time.deltaTime;

foreach(SceneryLayer layer in scenery)

{

layer.UpdateBlocks(speed);

}

}

}

Acest script m-a ajutat la crearea unui efect convingator iar partea finala a codului opreste miscarea fundalului odata cu oprirea jocului.

Odata ce jocul este continuat efectul va reveni fara a fi nevoie de alte apeluri din partea utilizatorului.

Cladirile create sunt similare cu tema jocului ,iar codul binar este un element care l-am adaugat pentru a spori gandirea de „viitor” sau circuite .

Acest lucru l-am preluat din trendul „cyber-punk” in care tema principala sau imaginea vizuala este de un viitor dominat de tehnologie sau elemente cibernetice.

Pe langa fundalul jocului, elementele importante sunt blocurile pe care jucatorul va controla persoanjul si obstacolele care sunt raspandite prin nivel.Aceste texturi de blocuri leam creat in Photoshop folosind un numar redus de culor pentru a nu distrage atentia jucatorului si pentru a fi in viziunea de „pixel art”. Acest lucru ajuta la legarea tuturor elementelor scenei intr-o imagine cat mai „imbinata” din punct de vedere tematic.

In Unity tool am creat obiecte 2D la care le-am atribuit componenta de sprite la care s-au adaugat texturile create in Photoshop.Acestea sunt create manual folosind rezolutie intre 32×32 pixeli pentru blocurile mici pana la 128×32 pentru cele mari.

La aceste obiecte am atasat si o componenta de coliziune pentru ca caracterul sa nu treaca prin ele in timp ce se misca in nivel,precum si ca personajul sa „moara” daca se loveste de acestea.

Jocul este impartit in scene . Fiecare scene contine diferite tipuri de blocuri care sunt adaugate aleatoriu.
Scena a fost asamblata dupa gandirea mea iar dupa terminarea tuturor scenelor,le-am combinat pentru a face o tranzactie cat mai fluida.

Pe masura ce avanseaza caracterul scenele sunt asamblate in fata lui,iar cele prin care a trecut se vor sterge.Acest mod reduce cantitatea de memorie folosita de joc ,permitandu-mi sa creez scenele cum doresc.

Caracterul a fost creat folosint o imagine de 30×30 pixeli.Acest lucru mi-a fost posibil folosind unealta „creion” in Photoshop care are diametrul de un pixel si am desenat manual conturul.

Restul corpului a fost colorat folosindu-ma de procedeul numit „dithering”.

Folosindu-ma de editorul de sprite din Unity am putut crea mai multe cadre din animatia caracterului intr-un singur fisier.Acest lucru reduce considerabil marimea fisierului .

Aceste cadre au fost importate apoi in motorul de animare Unity, unde miscarea am salvat-o ca fisiere .anim .Acesta a fost apoi introdus in modulul animator Unity.

Aici am putut sa manipulez diferitele statuturi de animatie,de la statutul de mers sa fie tranzitie la statutul de saritura sau alte actiuni.

Nu am dat caracterului animatie de saritura deoarece ,in opinia mea,crea un element mai complex intr-o scena relativ simpla.

Desi animatia de saritura a fost stearsa,am dorit sa las o animatie sau efect de distrugere care intervine cand caracterul loveste un bloc din scena.

Acest efect la-am creat folosint sistemul de particule integrat in Unity care,legat la un script declansator creaza un efect de explozie in blocuri mai mici cand caracterul „moare”.

void KillPlayer()

{

Transform particles = (Transform)Instantiate(deathParticles, transform.position, transform.rotation);

Destroy(particles.gameObject, 2.0f);

OnPlayerDeath();

}

Rezultatul scriptului este un efect de particule simplu si fluid

Pentru a verifica daca caracterul se loveste de un obiect sau nu reuseste sa sara peste groapa ,trebuia analizata pozitia acestuia pe ecran .

Daca pozitia caracterului nu este pe ecran acesta este „omorat” si jocul se reseteaza.

Am folosit metodade crearea aunui cer in jurul picioarelor personajului pentru a verifica contactul cu solul sau daca loveste obiectele.

bool IsPlayerOffscreen()

{

float screenBottomEdge = -Camera.main.orthographicSize;

float ScreenLeftEdge = -Camera.main.aspect * Camera.main.orthographicSize;

return (transform.position.x + playerSize < ScreenLeftEdge ||

transform.position.y + playerSize < screenBottomEdge);

}

void OnTriggerEnter2D(Collider2D other)

{

if(isDead)

return;

if(other.CompareTag("Spikes") && !isInvincible)

{

KillPlayer();

}

}

Sunetele au fost preluate dintr-o baza de date de sunete simple „stock” care au fost procesate si manipulate in motorul audio din Unity.

Acestea sunt de mici dimensiuni ,de o complexitate redusa.

Formatul sunetelor este de tip .wav iar melodia ce se aude in fundal in timpul jocului este pusa sa fie rulata intr-o bucla.

Sunetele le-am legat de restul jocului prin scripturi de sunete.

Acestea pot fi de tip declansator pentru actiuni specifice ,cum este „moartea” caracterului.

public static void PlaySfx(string sfxName)

{

if(soundMan == null)

{

return;

}

soundMan.PlaySound(sfxName, soundMan.sounds, soundMan.sfxAudio);

}

Acest script leaga sunetul de actiunea de coliziune a personajului si de particulele rezultate in urma coliziunii,rezultand intr- un efect mai complet.

Mai exista si scripturi care redau sunete constant,care l-am folosit pentru redarea melodiei de fundal in timpul rularii.

public static void PlayMusic(string trackName)

{

if(soundMan == null)

{

return;

}

soundMan.musicAudio.time = 0.0f;

soundMan.musicAudio.volume = 1.0f;

soundMan.PlaySound(trackName, soundMan.music, soundMan.musicAudio);

}

Acest cod reda musica doar in timpul jocului ,aceasta fiind oprita in meniu sau la oprirea rularii.

Indiferent de joc ,simplu sau complex, el are nevoie de o interfata grafica care sa ii permita utilizatorului optiuni precum „iesire” sau „incepere”.

Pentru acest joc am creat o interfata grafica simpla dar intuitiva,perfecta pentru platforma mobila.

Fiindca majoritatea telefoanelor mobile din ziua de azi dispun de ecran tactil,am introdus un simplu buton care incepe jocul la o simpla atingere.

In partea centrala am plasat o mica descriere a jocului precum controlul personajului si un buton de pauza.

Cand personajul „moare” ,jocul va rula meniul de iesire sau restartare a rularii.

Pe langa acestea este afisat si recordul de distanta precum si cea parcursa in ultima incercare.

La apasarea butonului „restart” jocul o ia de la capat pana la urmatoarea „moarte” sau pana la inchiderea aplicatiei de catre utilizator.

Toate aceastea au fost posibile utilizand scriptarea ,si anume scriptare de UI sau interfata.

public class FinishMenu : MonoBehaviour

{

public GameObject gameOverText;

public GameObject score;

public GameObject exitButton;

public GameObject restartButton;

public GameObject screenFade;

public TextMesh distanceText;

public TextMesh bestText;

private Color fadeCol = new Color(0,0,0, 0.5f);

public void Activate()

{

// textul distantei

distanceText.text = GameManager.Game.LastScore.ToString() + "m";

bestText.text = GameManager.Game.BestScore.ToString() + "m";

// pentru animarea elementelor pe ecran

MenuAnim.FadeTo(screenFade, fadeCol, 0.3f, 0.0f);

MenuAnim.MoveTo(gameOverText, new Vector3(0, 0.5f, 0), 0.4f, 0.0f);

MenuAnim.MoveTo(score, new Vector3(0, 0, 0), 0.4f, 0.1f);

MenuAnim.MoveTo(exitButton, new Vector3(-1.35f, -1.5f, 0), 0.4f, 0.3f);

MenuAnim.MoveTo(restartButton, new Vector3(1.35f, -1.5f, 0), 0.4f, 0.3f);

SoundManager.PauseMusic(0.5f);

}

Acest cod face parte din scriptul meniului de final care apare atunci cand personajul „moare”.

Toate aceste coduri de UI sunt legate printr-o ierarhie de obiecte care lucreaza impreuna ,sub diferite circumstante(rulare,pauza etc).

La finalul crearii tuturor elementelor componente ale jocului de la scripturi la sunete si animatii,jocul este prezentat ca o „harta” unde toate elemetele sunt afisate la vederea dezvoltatorului

Aceste obiecte si efecte se pot manipula oricand la fel de usor ca la inceputul proiectului.

Dupa terminarea testarii in emulatorul Android si rularii jocului de cateva ori,l-am exportat ca format .apk si l-am testat inca o data pe telefonul propriu.

Jocul ruleaza bine si performantele sunt ridicate,deci pentru mine a fost un succes avand in vedere ca este primul joc creat.

Concluzii

In final,am reusit sa creez ce mi-am dorit.Desi pe parcursul acestui proiect ideile mele au fost alterate ,produsul final este incadrat in viziunea care am avut-o la inceput.

Poate ca jocul putea fi mai complex,sau mai colorat dar tema cea mai importanta a jocului a fost simplitatea si usurinta jocului.

In zilele noastre multe companii incearca sa creeze jocuri cat mai complexe si mai realiste,dar uita un lucru important ,distractia.

Jocurile sunt facute pentru a da o stare de bucurie.Sunt facute pentru a ajuta ,chiar daca pentru un timp scurt, sa uite de problemele din viata de zi cu zi a fiecarui om si sa se relaxeze intr-un mediu placut.

Pentru mine, jocul realizat face acest lucru reusind astfel sa faca jucatorii sa isi aduca aminte de jocurile de odinioara cand „gameplayul” jocului era mai important decat realismul sau grafica sa.

Iar jocul prezentat mai sus face acest lucru prin crearea unui mediu simplu si distractiv fara distrage atentia cu alte elemente nesemnificative.

Similar Posts