I 10 errori più comuni che fanno gli sviluppatori di Unity

Pubblicato: 2022-03-11

Unity è uno strumento fantastico e semplice da utilizzare per lo sviluppo multipiattaforma. I suoi principi sono facili da capire e puoi iniziare intuitivamente a creare i tuoi prodotti. Tuttavia, se alcune cose non vengono prese in considerazione, rallenteranno i tuoi progressi quando procedi con il tuo lavoro al livello successivo, mentre stai passando dalla fase iniziale del prototipo o ti stai avvicinando a una versione finale. Questo articolo fornirà consigli su come superare i problemi più comuni e su come evitare errori fondamentali nei tuoi progetti nuovi o esistenti. Tieni presente che la prospettiva di questo articolo è più focalizzata sullo sviluppo di applicazioni 3D, ma tutto ciò che è menzionato è applicabile anche allo sviluppo 2D.

Unity è uno strumento fantastico e semplice da utilizzare per lo sviluppo multipiattaforma.
Twitta

Errore di unità comune n. 1: sottovalutare la fase di pianificazione del progetto

Per ogni progetto, è fondamentale determinare diverse cose prima ancora che inizi la progettazione dell'applicazione e la parte di programmazione del progetto. Al giorno d'oggi, quando il marketing del prodotto è una parte importante dell'intero processo, è anche importante avere un'idea chiara di quale sarà il modello di business dell'applicazione implementata. Devi essere sicuro per quali piattaforme rilascerai il prodotto e quali piattaforme sono nel tuo piano. È anche necessario impostare le specifiche minime dei dispositivi supportati (supporterai i vecchi dispositivi di fascia bassa o solo i modelli più recenti?) per avere un'idea di quali prestazioni e immagini puoi permetterti. Ogni argomento in questo articolo è influenzato da questo fatto.

Da un punto di vista più tecnico, dovrebbe essere necessario impostare in anticipo l'intero flusso di lavoro di creazione di asset e modelli fornendoli al programmatore, con particolare attenzione al processo di iterazione quando i modelli avranno bisogno di ulteriori modifiche e perfezionamenti. Dovresti avere un'idea chiara della frequenza dei fotogrammi e del budget dei vertici desiderati, in modo che l'artista 3D possa sapere in quale risoluzione massima devono essere i modelli e quante variazioni LOD deve fare. Dovrebbe anche essere specificato come unificare tutte le misurazioni per avere una scala coerente e il processo di importazione nell'intera applicazione.

Il modo in cui verranno progettati i livelli è fondamentale per il lavoro futuro perché la divisione dei livelli influenza molto le prestazioni. I problemi di prestazioni devono essere sempre presenti quando si progettano nuovi livelli. Non andare con visioni irrealistiche. È sempre importante porsi la domanda "può essere ragionevolmente raggiunto?" In caso contrario, non dovresti sprecare le tue preziose risorse in qualcosa di difficilmente realizzabile (nel caso in cui non faccia parte della tua strategia di business averlo come principale vantaggio competitivo, ovviamente).

Errore di unità comune n. 2: lavorare con modelli non ottimizzati

È fondamentale avere tutti i modelli ben preparati per poterli utilizzare nelle scene senza ulteriori modifiche. Ci sono molte cose che il buon modello dovrebbe soddisfare.

È importante impostare correttamente la bilancia. A volte non è possibile impostarlo correttamente dal software di modellazione 3D a causa delle diverse unità utilizzate da queste applicazioni. Per aggiustare tutto, imposta il fattore di scala nelle impostazioni di importazione dei modelli (lascia 0.01 per 3dsMax e Modo, imposta 1.0 per Maya) e nota che a volte dovrai reimportare gli oggetti dopo aver modificato l'impostazione della scala. Queste impostazioni dovrebbero garantire che puoi utilizzare solo la scala di base 1,1,1 nelle tue scene per ottenere un comportamento coerente e nessun problema di fisica. È più probabile che anche il batch dinamico funzioni correttamente. Questa regola dovrebbe essere applicata anche a ogni sottooggetto nel modello, non solo a quello principale. Quando devi modificare le dimensioni degli oggetti, fallo per quanto riguarda altri oggetti nell'applicazione di modellazione 3D piuttosto che in Unity. Tuttavia, puoi sperimentare la scalabilità in Unity per trovare i valori appropriati, ma per l'applicazione finale e un flusso di lavoro coerente, è bene avere tutto ben preparato prima di importare in Unity.

Per quanto riguarda la funzionalità dell'oggetto e le loro parti dinamiche, dividi bene i tuoi modelli. Meno oggetti secondari, meglio è. Separa le parti dell'oggetto nel caso in cui ne hai bisogno, ad esempio, per spostarsi o ruotare in modo dinamico, per scopi di animazione o altre interazioni. Ogni oggetto e i suoi sottooggetti dovrebbero avere il perno correttamente allineato e ruotato rispetto alla sua funzione principale. L'oggetto principale dovrebbe avere l'asse Z rivolto in avanti e il perno dovrebbe trovarsi nella parte inferiore dell'oggetto per un migliore posizionamento nella scena. Usa il minor numero possibile di materiali sugli oggetti (più su questo sotto).

Tutte le risorse dovrebbero avere nomi propri che ne descrivano facilmente il tipo e la funzionalità. Mantieni questa coerenza in tutti i tuoi progetti.

Errore di unità comune n. 3: costruire un'architettura di codice interdipendente

La prototipazione e l'implementazione di funzionalità in Unity è abbastanza semplice. Puoi facilmente trascinare e rilasciare qualsiasi riferimento ad altri oggetti, indirizzare ogni singolo oggetto nella scena e accedere a ogni componente che ha. Tuttavia, questo può anche essere potenzialmente pericoloso. Oltre a problemi di prestazioni evidenti (trovare un oggetto nella gerarchia e l'accesso ai componenti ha il suo sovraccarico), c'è anche un grande pericolo nel rendere le parti del codice completamente dipendenti l'una dall'altra. O dipendere da altri sistemi e script unici per la tua applicazione, o anche dalla scena attuale o dallo scenario attuale. Prova ad adottare un approccio più modulare e crea parti riutilizzabili che possono essere utilizzate in altre parti della tua applicazione o anche condivise nell'intero portafoglio di applicazioni. Crea il tuo framework e le tue librerie su Unity API nello stesso modo in cui stai costruendo la tua knowledge base.

Ci sono molti approcci diversi per garantire questo. Un buon punto di partenza è il sistema di componenti Unity stesso. Possono verificarsi complicazioni quando particolari componenti devono comunicare con altri sistemi dell'applicazione. Per questo, puoi utilizzare le interfacce per rendere le parti del tuo sistema più astratte e riutilizzabili. In alternativa, è possibile utilizzare un approccio basato sugli eventi per reagire a eventi particolari dall'esterno dell'ambito, creando un sistema di messaggistica o registrando direttamente parti dell'altro sistema come listener. L'approccio corretto sarà provare a separare le proprietà di gameObject dalla logica del programma (almeno qualcosa come il principio del controller del modello), perché è difficile identificare quali oggetti stanno modificando le sue proprietà di trasformazione, come la posizione e la rotazione. Dovrebbe essere esclusivamente responsabilità del suo responsabile del trattamento.

Cerca di documentare tutto bene. Trattalo sempre come se dovessi tornare al tuo codice dopo molto tempo e devi capire rapidamente cosa sta facendo esattamente questa parte del codice. Perché in realtà, molto spesso arriverai ad alcune parti della tua applicazione dopo un po' di tempo ed è un ostacolo inutile per saltare rapidamente nel problema. Ma non esagerare. A volte è sufficiente una classe, un metodo o un nome di proprietà appropriati.

Errore di unità comune n. 4: sprecare le tue prestazioni

L'ultima linea di prodotti di telefoni cellulari, console o computer desktop non sarà mai così avanzata da non dover preoccuparsi delle prestazioni. Le ottimizzazioni delle prestazioni sono sempre necessarie e forniscono le basi per fare la differenza nell'aspetto del tuo gioco o applicazione rispetto ad altri sul mercato. Perché quando salvi alcune prestazioni in una parte, puoi usarle per lucidare altre parti della tua applicazione.

Ci sono molte aree per le ottimizzazioni. L'intero articolo sarebbe necessario solo per scalfire la superficie su questo argomento. Almeno, cercherò di dividere questo dominio in alcune aree principali.

Aggiorna cicli

Non usare cose ad alta intensità di prestazioni nei cicli di aggiornamento, usa invece la memorizzazione nella cache. Un tipico esempio è l'accesso a componenti o altri oggetti in una scena o calcoli intensivi negli script. Se possibile, memorizza tutto nella cache nei metodi Awake() o cambia la tua architettura in un approccio più basato sugli eventi per attivare le cose proprio quando sono necessarie.

Istanziazioni

Per gli oggetti che vengono istanziati abbastanza spesso (ad esempio, proiettili in un gioco FPS), creane un pool preinizializzato e scegline uno già inizializzato quando ne hai bisogno e attivalo. Quindi, invece di distruggerlo quando non è più necessario, disattivalo e rimettilo in piscina.

Rendering

Usa l'eliminazione dell'occlusione o le tecniche LOD per limitare le parti renderizzate della scena. Prova a utilizzare modelli ottimizzati per essere in grado di tenere sotto controllo il conteggio dei vertici nella scena. Tieni presente che il conteggio dei vertici non è solo il numero di vertici sul modello stesso, ma è influenzato da altre cose come le normali (spigoli vivi), le coordinate UV (cuciture UV) e i colori dei vertici. Inoltre, un certo numero di luci dinamiche nella scena influenzeranno notevolmente le prestazioni complessive, quindi cerca di preparare tutto in anticipo quando possibile.

Disegna chiamate

Cerca di ridurre il conteggio delle chiamate di estrazione. In Unity, puoi ottenere una riduzione delle chiamate di disegno utilizzando il batch statico per gli oggetti fissi e il batch dinamico per quelli in movimento. Tuttavia, devi prima preparare le scene e i modelli (gli oggetti in batch devono condividere gli stessi materiali) e il batch di oggetti dinamici funziona solo per i modelli a bassa risoluzione. In alternativa, puoi combinare le mesh dallo script in una ( Mesh.CombineMeshes ) invece di utilizzare il batch, ma devi fare attenzione a non creare oggetti troppo grandi che non possono trarre vantaggio dall'eliminazione del frustum su alcune piattaforme. In generale, la chiave è usare il minor materiale possibile e condividerli sulla scena. A volte sarà necessario creare atlanti dalle trame per poter condividere un materiale tra oggetti distinti. Un buon consiglio è anche quello di utilizzare una risoluzione maggiore delle trame delle mappe di luce della scena (risoluzione non generata, ma risoluzione dell'output della trama) per ridurne il numero quando si prepara la luce in ambienti più ampi.

Problemi di scoperto

Non utilizzare trame trasparenti quando non è necessario, poiché causerebbe problemi di riempimento. Va bene usarlo per geometrie complicate e più distanti, come alberi o cespugli. Quando è necessario utilizzarlo, preferire gli shader alpha blended invece degli shader con alpha test o invece degli shader cutout per piattaforme mobili. Per identificare questi problemi in generale, prova ad abbassare la risoluzione della tua applicazione. Se può essere d'aiuto, potrebbe essere possibile che tu abbia questi problemi di riempimento o sia necessario ottimizzare maggiormente gli shader. Altrimenti, può essere un problema di memoria in più.

Shader

Ottimizza i tuoi shader per prestazioni migliori. Riduci il numero di passaggi, utilizza le variabili con minore precisione, sostituisci complicati calcoli matematici con texture di ricerca pregenerate.

Utilizzare sempre un profiler per determinare i colli di bottiglia. È un ottimo strumento. Per il rendering, puoi anche utilizzare il fantastico Frame Debugger, che ti aiuterà a imparare molto su come funzionano le cose in generale quando scomponi i processi di rendering con esso.

Errore di unità comune n. 5: ignorare i problemi di Garbage Collection

È necessario rendersi conto che, nonostante Garbage Collector (GC) stesso ci aiuti a essere davvero efficienti e concentrati su cose importanti nella programmazione, ci sono alcune cose di cui dovremmo essere esplicitamente consapevoli. L'utilizzo di GC non è gratuito. In generale, dovremmo evitare allocazioni di memoria non necessarie per evitare che GC si attivi troppo spesso e quindi rovini le prestazioni a causa di picchi di framerate. Idealmente, non dovrebbero esserci nuove allocazioni di memoria che si verificano regolarmente ogni frame. Tuttavia, come possiamo raggiungere questo obiettivo? È davvero determinato dall'architettura dell'applicazione, ma ci sono alcune regole che potresti seguire che aiutano:

  • Evita allocazioni non necessarie nei cicli di aggiornamento.
  • Usare struct per contenitori di proprietà semplici, poiché non sono allocati nell'heap.
  • Prova a preallocare array o elenchi o altre raccolte di oggetti, invece di crearli all'interno di cicli di aggiornamento.
  • Evita di utilizzare elementi mono problematici (come le espressioni LINQ o i cicli foreach, ad esempio) perché Unity utilizza una versione di Mono precedente, non idealmente ottimizzata (al momento della stesura è la versione modificata 2.6, con aggiornamento sulla roadmap).
  • Stringhe di cache nei metodi Awake() o negli eventi.
  • Se è necessario l'aggiornamento della proprietà della stringa nel ciclo di aggiornamento, utilizzare l'oggetto StringBuilder anziché la stringa.
  • Usa il profiler per identificare potenziali problemi.

Errore di unità comune n. 6: ottimizzazione dell'utilizzo della memoria e dello spazio per ultimo

È necessario mantenere l'attenzione sull'utilizzo minimo di memoria e spazio dell'applicazione dall'inizio del progetto, poiché è più complicato farlo quando si esce dall'ottimizzazione per la fase di pre-release. Sui dispositivi mobili, questo è ancora più importante, perché lì le risorse sono piuttosto scarse. Inoltre, superando le dimensioni di 100 MB dell'installazione, possiamo perdere una quantità significativa dei nostri clienti. Ciò è dovuto al limite di 100 MB per i download dalla rete cellulare e anche per motivi psicologici. È sempre meglio quando la tua applicazione non spreca le preziose risorse telefoniche dei clienti e sarà più probabile che scarichino o acquistino la tua app quando le sue dimensioni sono inferiori.

Per trovare i prosciugatori di risorse, puoi utilizzare il registro dell'editor dove puoi vedere (dopo ogni nuova build) la dimensione delle risorse suddivise in categorie separate, come audio, trame e DLL. Per un migliore orientamento, ci sono estensioni dell'editor su Unity Asset Store, che ti forniranno un riepilogo dettagliato con risorse e file di riferimento nel tuo filesystem. Il consumo di memoria effettivo può essere visto anche nel profiler, ma si consiglia di testarlo quando connesso per creare sulla piattaforma di destinazione perché ci sono molte incoerenze durante il test in un editor o su qualsiasi cosa diversa dalla piattaforma di destinazione.

I maggiori consumatori di memoria sono spesso le texture. Preferibilmente, usa le trame compresse poiché occupano molto meno spazio e memoria. Rendi tutte le trame al quadrato, idealmente, rendi la lunghezza di entrambi i lati potenza di due (POT), ma tieni presente che Unity può anche ridimensionare automaticamente le trame NPOT su POT. Le trame possono essere compresse quando sono nel modulo POT. Atlas trame insieme per riempire l'intera trama. A volte puoi persino utilizzare il canale alfa delle texture per alcune informazioni extra per i tuoi shader per risparmiare spazio e prestazioni aggiuntivi. E, naturalmente, prova a riutilizzare le trame per le tue scene il più possibile e usa le trame ripetute quando è possibile mantenere un buon aspetto visivo. Per i dispositivi di fascia bassa, puoi ridurre la risoluzione delle trame in Impostazioni qualità. Usa il formato audio compresso per clip audio più lunghe, come la musica di sottofondo.

Quando hai a che fare con piattaforme, risoluzioni o localizzazioni diverse, puoi utilizzare bundle di risorse per utilizzare diversi set di trame per dispositivi o utenti diversi. Questi bundle di risorse possono essere caricati dinamicamente da Internet dopo l'installazione dell'applicazione. In questo modo, puoi superare il limite di 100 MB scaricando le risorse durante il gioco.

Errore di unità comune n. 7: errori di fisica comuni

A volte, quando spostiamo oggetti nella scena, non ci rendiamo conto che l'oggetto ha un collisore su di esso e che cambiare la sua posizione costringerà il motore a ricalcolare di nuovo l'intero mondo fisico. In tal caso, dovresti aggiungere il componente Rigidbody (puoi impostarlo su non cinematico se non vuoi che siano coinvolte forze esterne).

Per modificare la posizione dell'oggetto con Rigidbody su di esso, impostare sempre Rigidbody.position quando una nuova posizione non segue la precedente, oppure Rigidbody.MovePosition quando si tratta di un movimento continuo, che tiene conto anche dell'interpolazione. Quando lo modifichi, applica le operazioni sempre in FixedUpdate , non nelle funzioni di Update . Garantirà comportamenti fisici coerenti.

Se possibile, usa collider primitivi su oggetti di gioco, come sfere, scatole o cilindri, e non collider mesh. Puoi comporre il tuo collisore finale da più di uno di questi collisori. La fisica può essere un collo di bottiglia delle prestazioni dell'applicazione a causa del sovraccarico della CPU e le collisioni tra i collider primitivi sono molto più veloci da calcolare. Puoi anche regolare l'impostazione Passo temporale fisso in Gestione tempo per ridurre la frequenza degli aggiornamenti fissi della fisica quando l'accuratezza dell'interazione fisica non è così necessaria.

Errore di unità comune n. 8: testare manualmente tutte le funzionalità

A volte potrebbe esserci la tendenza a testare manualmente la funzionalità sperimentando nella modalità di gioco perché è piuttosto divertente e hai tutto sotto il tuo diretto controllo. Ma questo fattore interessante può diminuire abbastanza rapidamente. Più l'applicazione diventa complessa, più le attività noiose che il programmatore deve ripetere ea cui pensare per assicurarsi che l'applicazione si comporti come originariamente previsto. Può facilmente diventare la parte peggiore dell'intero processo di sviluppo, a causa del suo carattere ripetitivo e passivo. Inoltre, poiché la ripetizione manuale degli scenari di test non è così divertente, quindi c'è una maggiore possibilità che alcuni bug superino l'intero processo di test.

Unity ha ottimi strumenti di test per automatizzare questo. Con un'adeguata progettazione architettonica e del codice, puoi utilizzare unit test per testare funzionalità isolate o anche test di integrazione per testare scenari più complessi. È possibile ridurre drasticamente l'approccio try-and-check in cui si registrano i dati effettivi e li si confronta con lo stato desiderato.

Il test manuale è senza dubbio una parte critica dello sviluppo. Ma la sua quantità può essere ridotta e l'intero processo può essere più robusto e veloce. Quando non è possibile automatizzarlo, prepara le scene di prova per poter affrontare il problema che stai cercando di risolvere il più rapidamente possibile. Idealmente, alcuni fotogrammi dopo aver premuto il pulsante di riproduzione. Implementa scorciatoie o trucchi per impostare lo stato desiderato per il test. Inoltre, isola la situazione di test per essere sicuro della causa del problema. Ogni secondo non necessario nella modalità di riproduzione quando il test viene accumulato e maggiore è la distorsione iniziale del test del problema, più è probabile che non lo verificherai affatto e speri che tutto funzioni correttamente. Ma probabilmente non lo farà.

Errore comune di Unity n. 9: pensare che i plugin Unity Asset Store risolveranno tutti i tuoi problemi

Fidati di me; non lo faranno. Quando ho lavorato con alcuni clienti, a volte ho dovuto affrontare la tendenza o i relitti del passato di utilizzare i plug-in di asset store per ogni singola piccola cosa. Non voglio dire che non ci siano estensioni Unity utili su Unity Asset Store. Ce ne sono molti ea volte è persino difficile decidere quale scegliere. Ma per ogni progetto, è importante mantenere la coerenza, che può essere distrutta utilizzando incautamente pezzi diversi che non si adattano bene insieme.

D'altra parte, per funzionalità la cui implementazione richiederebbe molto tempo, è sempre utile utilizzare prodotti ben testati da Unity Asset Store, che possono farti risparmiare un'enorme quantità di tempo di sviluppo. Tuttavia, scegli attentamente, usa quelli collaudati che non porteranno molti bug incontrollabili e strani al tuo prodotto finale. Le recensioni a cinque stelle sono una buona misura per cominciare.

Se la funzionalità desiderata non è difficile da implementare, aggiungila alle tue librerie personali (o aziendali) in costante crescita, che possono essere riutilizzate in tutti i tuoi progetti in seguito. In questo modo migliorerai le tue conoscenze e il tuo set di strumenti allo stesso tempo.

Errore di unità comune n. 10: non avere bisogno di estendere la funzionalità di base di Unity

A volte può sembrare che l'ambiente di Unity Editor sia abbastanza sufficiente per i test di gioco di base e il level design, ed estenderlo è una perdita di tempo. Ma fidati, non lo è. Il grande potenziale di estensione di Unity deriva dalla capacità di adattarlo a problemi specifici che devono essere risolti in vari progetti. Ciò può migliorare l'esperienza dell'utente quando si lavora in Unity o accelerare notevolmente l'intero flusso di lavoro di sviluppo e progettazione dei livelli. Sarebbe un peccato non utilizzare le funzionalità integrate, come i cassetti delle proprietà integrati o personalizzati, i cassetti Decorator, le impostazioni dell'ispettore dei componenti personalizzati o anche non creare interi plug-in con le proprie finestre dell'editor.

Conclusione

Spero che questi argomenti ti siano utili mentre sposti ulteriormente i tuoi progetti Unity. Ci sono molte cose che sono specifiche del progetto, quindi non possono essere applicate, ma è sempre utile avere in mente alcune regole di base quando si cerca di risolvere problemi più difficili e specifici. Potresti avere opinioni o procedure diverse su come risolvere questi problemi nei tuoi progetti. La cosa più importante è mantenere i tuoi idiomi coerenti durante tutto il progetto in modo che chiunque nel tuo team possa capire chiaramente come il particolare dominio avrebbe dovuto essere risolto correttamente.


Ulteriori letture sul blog di Toptal Engineering:

  • Sviluppo di Unity AI: un tutorial sulla macchina a stati finiti