Cele mai frecvente 10 greșeli pe care le fac dezvoltatorii Unity

Publicat: 2022-03-11

Unity este un instrument excelent și simplu de utilizat pentru dezvoltarea multi-platformă. Principiile sale sunt ușor de înțeles și puteți începe intuitiv să vă creați produsele. Cu toate acestea, dacă unele lucruri nu sunt luate în considerare, acestea vă vor încetini progresul atunci când treceți cu munca la nivelul următor, pe măsură ce treceți de la faza inițială a prototipului sau vă apropiați de o versiune finală. Acest articol vă va oferi sfaturi despre cum să depășiți cele mai comune probleme și despre cum să evitați greșelile fundamentale în proiectele dvs. noi sau existente. Vă rugăm să rețineți că perspectiva acestui articol este axată mai mult pe dezvoltarea aplicațiilor 3D, dar tot ceea ce este menționat este aplicabil și pentru dezvoltarea 2D.

Unity este un instrument excelent și simplu de utilizat pentru dezvoltarea multi-platformă.
Tweet

Greșeala comună de unitate #1: Subestimarea fazei de planificare a proiectului

Pentru fiecare proiect, este esențial să determinați mai multe lucruri înainte de a începe chiar și proiectarea aplicației și partea de programare a proiectului. În zilele noastre, când marketingul de produs este o parte importantă a întregului proces, este, de asemenea, important să aveți o idee clară despre care va fi modelul de afaceri al aplicației implementate. Trebuie să fii sigur pentru ce platforme vei lansa produsul și ce platforme sunt în planul tău. De asemenea, este necesar să setați specificațiile minime pentru dispozitive acceptate (veți suporta dispozitive mai vechi de ultimă generație sau doar modele mai recente?) pentru a avea ideea ce performanță și imagini vă puteți permite. Fiecare subiect din acest articol este influențat de acest fapt.

Dintr-un punct de vedere mai tehnic, ar trebui să fie necesar să se stabilească în avans întregul flux de lucru al creării activelor și modelelor, oferindu-le programatorului, cu o atenție deosebită procesului de iterație atunci când modelele vor avea nevoie de câteva modificări și perfecționări suplimentare. Ar trebui să aveți o idee clară despre rata de cadre dorită și bugetul de vârf, astfel încât artistul 3D să poată ști în ce rezoluție maximă trebuie să fie modelele și câte variații LOD trebuie să facă. De asemenea, ar trebui specificat cum să unificați toate măsurătorile pentru a avea o scară consecventă și procesul de importare în întreaga aplicație.

Modul în care vor fi proiectate nivelurile este crucial pentru lucrările viitoare, deoarece împărțirea nivelului influențează foarte mult performanța. Preocupările privind performanța trebuie să fie întotdeauna în minte atunci când proiectați noi niveluri. Nu merge cu viziuni nerealiste. Este întotdeauna important să vă puneți întrebarea „poate fi atins în mod rezonabil?” Dacă nu, nu ar trebui să-ți irosești resursele prețioase pe ceva greu de realizabil (în cazul în care nu face parte din strategia ta de afaceri să-l ai drept principal avantaj competitiv, desigur).

Greșeala comună Unity #2: Lucrul cu modele neoptimizate

Este esențial să aveți toate modelele bine pregătite pentru a le putea folosi în scenele dvs. fără alte modificări. Există mai multe lucruri pe care modelul bun ar trebui să le îndeplinească.

Este important să setați corect scala. Uneori, nu este posibil să setați corect acest lucru din software-ul dvs. de modelare 3D din cauza diferitelor unități pe care aceste aplicații le folosesc. Pentru a face totul corect, setați factorul de scară în setările de import a modelelor (lăsați 0,01 pentru 3dsMax și Modo, setați 1,0 pentru Maya) și rețineți că uneori va trebui să reimportați obiecte după ce ați schimbat setarea de scară. Aceste setări ar trebui să vă asigure că puteți utiliza doar scara de bază 1,1,1 în scenele dvs. pentru a obține un comportament consistent și fără probleme de fizică. De asemenea, loturile dinamice vor funcționa corect. Această regulă ar trebui aplicată și pentru fiecare subobiect din model, nu doar pentru cel principal. Când trebuie să modificați dimensiunile obiectului, faceți acest lucru în ceea ce privește alte obiecte în aplicația de modelare 3D, mai degrabă decât în ​​Unity. Cu toate acestea, puteți experimenta cu scala în Unity pentru a afla valorile adecvate, dar pentru aplicarea finală și fluxul de lucru consistent, este bine să aveți totul bine pregătit înainte de a importa în Unity.

În ceea ce privește funcționalitatea obiectului și părțile lor dinamice - împărțiți bine modelele dvs. Cu cât sunt mai puține subobiecte, cu atât mai bine. Separați părți ale obiectului doar în cazul în care aveți nevoie de ele, de exemplu, pentru a vă muta sau roti dinamic, în scopuri de animație sau alte interacțiuni. Fiecare obiect și subobiectele sale ar trebui să aibă pivotul aliniat și rotit corespunzător în ceea ce privește funcția sa principală. Obiectul principal ar trebui să aibă axa Z îndreptată înainte, iar pivotul ar trebui să fie în partea de jos a obiectului pentru o mai bună plasare în scenă. Folosiți cât mai puține materiale pe obiecte (mai multe despre asta mai jos).

Toate activele ar trebui să aibă nume proprii care vor descrie cu ușurință tipul și funcționalitatea acestuia. Păstrați această consistență în toate proiectele dvs.

Greșeala comună de unitate nr. 3: Construirea unei arhitecturi de cod interdependente

Crearea de prototipuri și implementarea funcționalității în Unity este destul de ușoară. Puteți să trageți și să plasați cu ușurință orice referințe la alte obiecte, să vă adresați fiecărui obiect din scenă și să accesați fiecare componentă pe care o are. Cu toate acestea, acest lucru poate fi și potențial periculos. Pe lângă problemele de performanță vizibile (găsirea unui obiect în ierarhie și accesul la componente are o suprasarcină), există, de asemenea, un mare pericol în a face părți din codul dvs. complet dependente unele de altele. Sau să fii dependent de alte sisteme și scripturi unice pentru aplicația ta, sau chiar de scena curentă sau scenariul actual. Încercați să adoptați o abordare mai modulară și să creați părți reutilizabile care pot fi folosite în alte părți ale aplicației dvs. sau chiar partajate în întregul portofoliu de aplicații. Construiți-vă cadrul și bibliotecile pe deasupra API-ului Unity, în același mod în care vă construiți baza de cunoștințe.

Există o mulțime de abordări diferite pentru a asigura acest lucru. Un bun punct de plecare este sistemul de componente Unity în sine. Pot apărea complicații atunci când anumite componente trebuie să comunice cu alte sisteme ale aplicației. Pentru aceasta, puteți folosi interfețe pentru a face părți ale sistemului dvs. mai abstracte și mai reutilizabile. Alternativ, puteți utiliza o abordare bazată pe evenimente pentru a reacționa la anumite evenimente din afara domeniului de aplicare, fie prin crearea unui sistem de mesagerie, fie prin înregistrarea directă în părți ale celuilalt sistem ca ascultători. Abordarea corectă va fi încercarea de a separa proprietățile gameObject de logica programului (cel puțin ceva de genul principiului model-controler), deoarece este dificil să identifici ce obiecte modifică proprietățile de transformare, cum ar fi poziția și rotația. Ar trebui să fie responsabilitatea exclusivă a controlorului său.

Încercați să documentați totul bine. Tratează-l întotdeauna ca și cum ar trebui să revii la codul tău după mult timp și trebuie să înțelegi rapid ce face exact această parte a codului. Pentru că, în realitate, veți ajunge destul de des la unele părți ale aplicației dvs. după ceva timp și este un obstacol inutil pentru a trece rapid la problemă. Dar nu exagera cu asta. Uneori, o clasă adecvată, o metodă sau un nume de proprietate este suficient.

Greșeala obișnuită de unitate nr. 4: irosirea performanței

Cea mai recentă linie de produse de telefoane mobile, console sau computere desktop nu va fi niciodată atât de avansată încât să nu fie nevoie să-ți pese de performanță. Optimizările de performanță sunt întotdeauna necesare și oferă baza pentru a face diferența în ceea ce privește jocul sau aplicația dvs. în comparație cu altele de pe piață. Pentru că atunci când salvați o performanță într-o parte, o puteți folosi pentru a șlefui alte părți ale aplicației dvs.

Există o mulțime de zone pentru optimizări. Întregul articol ar fi nevoie doar pentru a zgâria suprafața despre acest subiect. Cel puțin, voi încerca să împart acest domeniu în câteva zone de bază.

Bucle de actualizare

Nu utilizați lucruri cu performanță intensivă în buclele de actualizare, folosiți în schimb memorarea în cache. Un exemplu tipic este accesul la componente sau alte obiecte dintr-o scenă sau calcule intensive în scripturile dumneavoastră. Dacă este posibil, stocați totul în cache în metodele Awake() sau schimbați-vă arhitectura la o abordare mai bazată pe evenimente pentru a declanșa lucrurile exact atunci când sunt necesare.

Instanciari

Pentru obiectele care sunt instanțiate destul de des (de exemplu, gloanțe într-un joc FPS), faceți un grup pre-inițializat din ele și alegeți unul deja inițializat atunci când aveți nevoie și activați-l. Apoi, în loc să-l distrugi când nu mai este necesar, dezactivează-l și returnează-l în bazin.

Redare

Utilizați tehnici de eliminare a ocluziei sau LOD pentru a limita părțile redate ale scenei. Încercați să utilizați modele optimizate pentru a putea menține sub control numărul de vârfuri din scenă. Fiți conștienți de faptul că numărul de vârfuri nu este doar numărul de vârfuri de pe modelul în sine, ci este influențat de alte lucruri precum valorile normale (margini dure), coordonatele UV (cusături UV) și culorile vârfurilor. De asemenea, o serie de lumini dinamice din scenă vor influența dramatic performanța generală, așa că încercați să coaceți totul în avans ori de câte ori este posibil.

Retrage apeluri

Încercați să reduceți numărul de apeluri la extragere. În Unity, puteți obține reducerea apelurilor prin utilizarea loturilor statice pentru obiectele nemișcate și a loturilor dinamice pentru cele aflate în mișcare. Cu toate acestea, trebuie să vă pregătiți mai întâi scenele și modelele (obiectele grupate trebuie să împartă aceleași materiale), iar lotul de obiecte dinamice funcționează numai pentru modelele de joasă rezoluție. Alternativ, puteți combina ochiuri în funcție de script într-una singură ( Mesh.CombineMeshes ) în loc să utilizați loturi, dar trebuie să aveți grijă să nu creați obiecte prea mari care să nu poată profita de tăierea frustum pe unele platforme. În general, cheia este să folosiți cât mai puține materiale posibil și să le împărtășiți în scenă. Va trebui uneori să creați atlase din texturi pentru a putea împărtăși un material între obiecte distincte. Un sfat bun este, de asemenea, să utilizați o rezoluție mai mare a texturilor hărților luminoase ale scenei (nu rezoluția generată, ci rezoluția de ieșire a texturii) pentru a reduce numărul acestora atunci când coaceți lumină în medii mai mari.

Probleme de overdraw

Nu utilizați texturi transparente atunci când nu este necesar, deoarece va cauza probleme cu rata de umplere. Este în regulă să-l folosiți pentru geometrii complicate și mai îndepărtate, cum ar fi copacii sau tufișurile. Când trebuie să-l utilizați, preferați shaderele amestecate alfa în loc de shadere cu testare alfa sau în locul shaderelor decupate pentru platformele mobile. Pentru a identifica aceste probleme în general, încercați să reduceți rezoluția aplicației dvs. Dacă vă ajută, este posibil să aveți aceste probleme cu rata de umplere sau să aveți nevoie să vă optimizați mai mult shaderele. În caz contrar, poate fi o problemă mai mare de memorie.

Shaders

Optimizați-vă shaderele pentru o performanță mai bună. Reduceți numărul de treceri, utilizați variabile cu o precizie mai mică, înlocuiți calculele matematice complicate cu texturi de căutare pre-generate.

Utilizați întotdeauna un profiler pentru a determina blocajele. Este un instrument grozav. Pentru randare, puteți folosi și minunatul Frame Debugger, care vă va ajuta să învățați multe despre cum funcționează lucrurile în general atunci când descompuneți procesele de randare cu acesta.

Greșeala comună Unity #5: Ignorarea problemelor de colectare a gunoiului

Este necesar să ne dăm seama că, în ciuda faptului că Garbage Collector (GC) în sine ne ajută să fim cu adevărat eficienți și concentrați pe lucruri importante în programare, există câteva lucruri de care ar trebui să fim conștienți în mod explicit. Utilizarea GC nu este gratuită. În general, ar trebui să evităm alocările inutile de memorie pentru a preveni GC să se declanșeze prea des și, astfel, să strice performanța prin vârfurile de framerate. În mod ideal, nu ar trebui să existe nicio alocare nouă de memorie în mod regulat pentru fiecare cadru. Cu toate acestea, cum putem atinge acest obiectiv? Este într-adevăr determinat de arhitectura aplicației, dar există câteva reguli pe care le puteți urma, care vă ajută:

  • Evitați alocările inutile în buclele de actualizare.
  • Folosiți structuri pentru containere de proprietăți simple, deoarece nu sunt alocate pe heap.
  • Încercați să prealocați matrice sau liste sau alte colecții de obiecte, în loc să le creați în bucle de actualizare.
  • Evitați să utilizați lucruri problematice mono (cum ar fi expresii LINQ sau bucle foreach, de exemplu), deoarece Unity folosește o versiune mai veche, nu optimizată în mod ideal de Mono (la momentul scrierii, este modificată versiunea 2.6, cu upgrade pe foaia de parcurs).
  • Cache șiruri în metodele Awake() sau în evenimente.
  • Dacă este necesară actualizarea proprietății șir în bucla de actualizare, utilizați obiectul StringBuilder în loc de șir.
  • Utilizați profiler pentru a identifica potențialele probleme.

Greșeala comună Unity #6: Optimizarea memoriei și a utilizării spațiului Ultimul

Este necesar să păstrați atenția asupra memoriei și spațiului cel mai scăzut al aplicației încă de la începutul proiectului, deoarece este mai complicat să o faceți atunci când lăsați optimizarea pentru faza de pre-lansare. Pe dispozitivele mobile, acest lucru este și mai important, deoarece avem destul de puține resurse acolo. De asemenea, depășind dimensiunea de 100 MB a instalării, putem pierde o cantitate semnificativă de clienți. Acest lucru se datorează limitei de 100 MB pentru descărcările din rețeaua celulară și, de asemenea, din motive psihologice. Este întotdeauna mai bine atunci când aplicația dvs. nu irosește resursele prețioase de telefon ale clienților, iar aceștia vor avea mai multe șanse să descarce sau să cumpere aplicația dvs. atunci când dimensiunea acesteia este mai mică.

Pentru a găsi scurgeri de resurse, puteți utiliza jurnalul editorului unde puteți vedea (după fiecare construcție nouă) dimensiunea resurselor împărțite în categorii separate, cum ar fi audio, texturi și DLL-uri. Pentru o orientare mai bună, există extensii de editor în Unity Asset Store, care vă vor oferi un rezumat detaliat cu resursele și fișierele la care se face referire în sistemul dvs. de fișiere. Consumul real de memorie poate fi văzut și în profiler, dar este recomandat să îl testați atunci când vă conectați pentru a construi pe platforma dvs. țintă, deoarece există o mulțime de inconsecvențe atunci când testați într-un editor sau pe orice altceva decât platforma țintă.

Cei mai mari consumatori de memorie sunt adesea texturile. De preferință, utilizați texturi comprimate, deoarece acestea ocupă mult mai puțin spațiu și memorie. Faceți toate texturile la pătrat, în mod ideal, faceți ca lungimea ambelor părți să devină putere de două (POT), dar rețineți că Unity poate scala texturile NPOT la POT automat. Texturile pot fi comprimate atunci când sunt în formă POT. Texturi Atlas împreună pentru a umple întreaga textură. Uneori, puteți chiar să utilizați canalul alfa de textură pentru informații suplimentare pentru shadere, pentru a economisi spațiu și performanță suplimentară. Și, desigur, încercați să reutilizați texturile pentru scenele dvs. cât mai mult posibil și folosiți texturi repetate atunci când este posibil să păstrați un aspect vizual bun. Pentru dispozitivele low-end, puteți reduce rezoluția texturilor în Setări de calitate. Utilizați formatul audio comprimat pentru clipuri audio mai lungi, cum ar fi muzica de fundal.

Când aveți de-a face cu diferite platforme, rezoluții sau localizări, puteți utiliza pachete de active pentru utilizarea diferitelor seturi de texturi pentru diferite dispozitive sau utilizatori. Aceste pachete de active pot fi încărcate dinamic de pe internet după ce aplicația a fost instalată. În acest fel, puteți depăși limita de 100 MB descărcând resurse în timpul jocului.

Greșeală comună Unity #7: Greșeli comune de fizică

Uneori, când mișcăm obiecte în scenă, nu realizăm că obiectul are un ciocnitor pe el și că schimbarea poziției lui va forța motorul să recalculeze întreaga lume fizică din nou. În acest caz, ar trebui să adăugați o componentă Rigidbody (o puteți seta la non-cinematic dacă nu doriți să fie implicate forțe externe).

Pentru a modifica poziția obiectului cu Rigidbody pe el, setați întotdeauna Rigidbody.position când o nouă poziție nu o urmează pe cea anterioară, sau Rigidbody.MovePosition când este o mișcare continuă, care ține cont și de interpolare. Când îl modificați, aplicați operațiunile întotdeauna în FixedUpdate , nu în funcțiile Update . Va asigura comportamente fizice consistente.

Dacă este posibil, utilizați colidere primitive pe obiecte de joc, cum ar fi sferă, cutie sau cilindru, și nu colisionare cu plasă. Puteți compune colisionarul final din mai multe dintre aceste colisionare. Fizica poate fi un blocaj de performanță al aplicației dvs. din cauza supraîncărcării CPU și coliziunile dintre colisionarele primitive sunt mult mai rapid de calculat. De asemenea, puteți ajusta setarea Fixed Timestep în Time manager pentru a reduce frecvența actualizărilor fixe ale fizicii atunci când acuratețea interacțiunii fizicii nu este atât de necesară.

Greșeala comună Unity #8: Testarea manuală a tuturor funcționalităților

Uneori ar putea exista tendința de a testa manual funcționalitatea experimentând în modul de redare, deoarece este destul de distractiv și ai totul sub controlul tău direct. Dar acest factor cool poate scădea destul de repede. Cu cât aplicația devine mai complexă, cu atât programatorul trebuie să repete și să se gândească la sarcinile mai obositoare pentru a se asigura că aplicația se comportă așa cum a fost intenționat inițial. Poate deveni cu ușurință cea mai proastă parte a întregului proces de dezvoltare, datorită caracterului său repetitiv și pasiv. De asemenea, pentru că repetarea manuală a scenariilor de testare nu este atât de distractivă, deci există o șansă mai mare ca unele erori să treacă prin întregul proces de testare.

Unity are instrumente excelente de testare pentru a automatiza acest lucru. Cu un design arhitectural și de cod adecvat, puteți utiliza teste unitare pentru testarea funcționalității izolate sau chiar teste de integrare pentru testarea scenariilor mai complexe. Puteți reduce dramatic abordarea de încercare și verificare în care înregistrați datele reale și le comparați cu starea dorită.

Testarea manuală este, fără îndoială, o parte critică a dezvoltării. Dar cantitatea sa poate fi redusă, iar întregul proces poate fi mai robust și mai rapid. Când nu există nicio modalitate posibilă de automatizare, pregătiți-vă scenele de testare pentru a putea intra în problema pe care încercați să o rezolvați cât mai repede posibil. În mod ideal, câteva cadre după apăsarea butonului de redare. Implementați comenzi rapide sau trucuri pentru a seta starea dorită pentru testare. De asemenea, izolați situația de testare pentru a fi sigur ce cauzează problema. În fiecare secundă inutilă în modul de redare când se acumulează testarea, și cu cât este mai mare părtinirea inițială a testării problemei, cu atât este mai probabil să nu testați deloc problema și veți spera că totul funcționează bine. Dar probabil că nu va fi.

Greșeala comună Unity #9: Gândește-te că pluginurile Unity Asset Store îți vor rezolva toate problemele

Aveți încredere în mine; nu vor. Când lucram cu unii clienți, uneori m-am confruntat cu tendința sau vestigiile din trecut de a folosi pluginuri pentru magazinul de active pentru fiecare lucru mic. Nu vreau să spun că nu există extensii Unity utile în Unity Asset Store. Sunt multe dintre ele, iar uneori chiar e greu să te decizi pe care să o alegi. Dar pentru fiecare proiect, este important să se păstreze consistența, care poate fi distrusă prin utilizarea neînțeleaptă a diferitelor piese care nu se potrivesc bine între ele.

Pe de altă parte, pentru funcționalitatea care ar dura mult timp pentru implementarea dvs., este întotdeauna util să utilizați produse bine testate de la Unity Asset Store, care vă pot economisi o cantitate imensă din timpul de dezvoltare. Cu toate acestea, alegeți cu atenție, folosiți-le pe cele dovedite, care nu vor aduce o mulțime de erori incontrolabile și ciudate produsului dvs. final. Recenziile de cinci stele sunt o măsură bună pentru început.

Dacă funcționalitatea dorită nu este greu de implementat, trebuie doar să o adăugați în bibliotecile personale (sau ale companiei) în continuă creștere, care pot fi folosite ulterior în toate proiectele dvs. În acest fel, vă îmbunătățiți cunoștințele și setul de instrumente în același timp.

Greșeala comună Unity #10: Nu este nevoie să extindeți funcționalitatea de bază Unity

Uneori poate părea că mediul Unity Editor este destul de suficient pentru testarea de bază a jocului și proiectarea nivelurilor, iar extinderea acestuia este o pierdere de timp. Dar crede-mă, nu este. Marele potențial de extindere al Unity vine din capacitatea de a-l adapta la probleme specifice care trebuie rezolvate în diverse proiecte. Acest lucru poate fie îmbunătăți experiența utilizatorului atunci când lucrează în Unity, fie poate accelera dramatic întregul flux de lucru de dezvoltare și design de nivel. Ar fi regretabil să nu folosiți funcții încorporate, cum ar fi Sertarele proprietăților încorporate sau personalizate, Sertarele decoratorului, setările personalizate ale inspectorului de componente sau chiar să nu construiți pluginuri întregi cu propriul Windows Editor.

Concluzie

Sper că aceste subiecte vă vor fi utile pe măsură ce vă mutați mai departe proiectele Unity. Există o mulțime de lucruri care sunt specifice proiectului, așa că nu pot fi aplicate, dar este întotdeauna util să aveți în vedere câteva reguli de bază atunci când încercați să rezolvați probleme mai dificile și mai specifice. Este posibil să aveți opinii sau proceduri diferite despre cum să rezolvați aceste probleme în proiectele dvs. Cel mai important este să vă păstrați idiomurile consecvente pe tot parcursul proiectului, astfel încât oricine din echipa dvs. să poată înțelege clar cum ar fi trebuit rezolvat corect domeniul respectiv.


Citiți suplimentare pe blogul Toptal Engineering:

  • Unity AI Development: Un tutorial de mașină cu stări finite