Registrarse

[Unity] Tips/Consejos profesionales para el buen desarrollo de aplicaciones en Unity Engine

Manurocker95

Doctorando en Ingeniería Biomédica & Game Dev
Miembro insignia
Bueno, lo dejo por aquí ya que no hay "Recursos" para Otras plataformas. Todos estos tips son de mi propia cosecha y lo que he ido aprendiendo como desarrollador profesional. Todo aporte es bienvenido.

NOTA: EN TODAS ESTAS NOTAS SE ASUME QUE TENÉIS CONOCIMIENTOS DE PROGRAMACIÓN Y DEL MOTOR. NO SE RESPONDERÁN DUDAS SOBRE ELLO, AUNQUE SÍ SOBRE LAS TIPS.

- Evitad a toda costa los métodos Invoke, Update, Get Component, Find y FindWithTag/OfType.

- Si necesitáis comprobar si un objeto tiene un componente attachado a él, usad "TryGetComponent" que solo aloca memoria si es true.

- CompareTag es más eficiente que ".tag == tag"

- Es absurdo guardar una variable GameObject para después hacer un GetComponent sobre él. Todo monobehavior tiene acceso a su gameObject y transform, por lo que guardad directamente la referencia a ese componente.

- El inspector está para algo. Si sabéis de antemano qué referencia necesitáis, es absurdo hacer un "GetComponent" en el Start/Awake. USAD EL INSPECTOR. Es recomendable hacer ese GetComponent tras comprobar que la referencia es nula.

- Para móviles, nunca aloquéis texturas mayores a 512x512 incluso si el máximo es muy superior (Ej: 4K para iPhone y 8K en los últimos Android).

- Siempre usad Atlas para TODAS las texturas posibles y siempre en texturas con tamaños múltiplos de 2. Una textura 512x512 se procesa muchísimo más rápido que una 124x130, aunque esta última sea más pequeña.

- Unity renderiza los objetos > materiales (shader) > texturas. Por lo tanto, un mismo material en 2 instancias con texturas distintas, es alocado 2 veces. Es recomendable en estos casos aplicar el toggle GPU Instancing si es posible para hacer batching en ellos.

- If/Else es generalmente más rápido que "switch" cuando hay más de 3 condiciones.

- Si vais a usar un terreno, siempre bakeadlo a una malla. El terreno de Unity está super mal optimizado.

- Siempre dividid el terreno/malla en chunks/pedazos y cargad y descargadlos según el gameplay lo requiera. Esto se va a notar excesivamente en Open-Worlds y semi Open-Worlds como pokémon, donde no hay pantallas de carga.

- Siempre bakead las luces para objetos estáticos. Las luces en tiempo real SOLO para objetos dinámicos.

- Siempre bakead el Occlusion Culling. Está ahí para evitar renderizar todo lo que no se ve.

- Todos los objetos estáticos, inclusive canvas, deben ser estáticos.

- No siempre es recomendable combinar las mallas. Pensad que solo se ocluyen aquellas mallas que "no se ven". Si están combinadas, al ver una parte, se renderiza ENTERO el objeto y por tanto, perdemos la optimización del OC. Sin embargo, muchas veces es recomendable combinarlos para ahorrar batches en el procesador.

- Si tenéis muchísimas instancias de un mismo game Object, u objetos con comportamientos similares (ej: Enemigos en hordas), es MUY recomendable el uso de Entity Component System (DOTS en Unity), que es un paradigma distinto: Data Oriented Programming, respecto al Object Oriented Programming de Monobehavior. Es absurdamente más eficiente para ello.

- Si no podéis usar DOTS + Burst, SIEMPRE usad Object Pooling. Es vuestra mejor baza. Gestionar la memoria toda junta es mucho mejor que ir trozeandola.

- Una alternativa difícil de implementar a estas dos opciones es usar la GPU para instanciar todo. Es muy complicado, pero es un punto intermedio.

- Instance y Destroy MATAN el framerate. Debéis usarlo en momentos muy puntuales y siempre que sea necesario.

- Evitad todo lo posible meter cualquier fichero en las carpetas "Resources". Esta solo reservadla para lo que vayáis sí o sí a hacer Resources.Load. Meter recursos aquí incrementa el espacio en la build absurdamente.

- Usad gestionadores de recursos como Asset Bundles, Bases de datos con Scriptable Objects o Addressables para cargar recursos. Son mucho mejor que Resources.Load. Aunque este último es más cómodo, es más ineficiente en la mayoría de casos. Además, no permite la desalocación manual de un recurso en memoria.

- Usad la menor resolución PARA TODO posible. Menos polígonos y menor calidad de texturas = más rápido de procesar. Evidentemente, queremos calidad, pero para eso existen los LODS.

- Existen los MipMaps. USADLOS.

- Como acabo de mencionar, usad siempre que sea posible los Levels of Detail. Todo lo que esté lejos, podéis tenerlo incluso con planos (Mirad el uso de Impostors).

- Batching de polígonos, materiales, texturas... SIEMPRE es recomendable, aunque tendréis que jugar con otras cosas.

- Todo recurso que ya no uséis, desalocadlo de la memoria. Si usáis addressables o asset bundles, esto lo podéis hacer fácilmente.

- Los atlas bundles son recomendables también.

- Aunque no optimicéis de primeras, tendréis que hacerlo al final, así que todo lo que hagáis en el proceso, os lo ahorráis al final.

- Para móviles y nintendo Switch, es MUY recomendable comprimir los audios (en las Settings del archivo en Unity) al 4%, que es el límite en el que suenan decentemente pero ahorran un huevo de espacio. No notaríais la diferencia incluso con auriculares.

- Si estáis alocando y desalocando audio, usad "Decompress on Load". Si tenéis audios permanentes (ej: Tener un SFX común), usad "Compress in Memory" en la Settings de Audio.

- Para VR, nintendo switch y móviles, nunca debéis tener renderizando más de 100.000 polígonos. Recordad que no es el poligonaje "real", si no el que vemos en stats. Que corresponde a los polígonos renderizados. Un material puede hacer que un objeto se renderice tantas veces como queramos y por tanto, afecte a esta cuenta.

- Las corrutinas son un gran sustituto al update, pero no son NADA mejores si vais a usarlo para cosas que vayan a comprobarse todos los frames. Son útiles cuando necesitáis control sobre cuando se activan y desactivan.

- Los Canvas están horrorosamente implementados, al igual que el terreno. Son absurdamente ineficientes. Usad Sprite siempre que sea posible (excepto la interfaz de usuario que necesitemos que sea escalable).

- Si usáis UnityEngine.UI, haced Untoggle de todos los Raycast Target que no necesitáis. Si un objeto no hace de "block" ni es interactuable, fuera ese raycast target". Menos procesos = mejor.

- NUNCA uséis Animator en objetos de un canvas. Unity refresca TODOS los objetos del canvas por cada elemento que tenga una animación CADA FRAME. Usad una librería de Tweening como DoTween para hacer animaciones en UI.

- "Preservable Aspect" en las UnityEngine.UI.Image es, por algún motivo, bastante más eficiente y rápido de procesar cuando se escala. Ej: Al usar una librería de tweening.

- Los Nested Canvas (un canvas hijo de otro en jerarquía) es bastante más eficiente que 2 canvas separados y más si ambos son escalables.

- Si necesitáis "realismo" en la luz, siempre usad Linear en el tipo de iluminación (Project Settings > Player). Si necesitáis performance, usad Gamma. Linear es poco recomendable para baja gama, móviles, switch y VR.

- Si no estáis renderizando un Skybox (porque una UI lo está tapando durante toda la ejecución de una escena, por ejemplo) haced que la cámara esté en "solid color". Unity renderiza si no el skybox aunque no se vea.

- El post-procesado hace que se vea bonito todo, pero consume demasiado. Usadlo solo para PC y Consolas y con MUCHA moderación.

- En vez de hacer un contador en update/corrutina, jugad si podéis con eventos y delegados. Te ahorra tiempo y recursos.

- Los Singleton son MUY cómodos. Debéis usarlos, pero siempre con moderación y sabiendo lo que hacen. Jugad con los Execution Orders de los scripts.

- Los scriptable objects son lo mejor para guardar información estática (ej: bases de datos). USADLOS.

- Para multijugador, cuando mandéis datos (ej: con Photon), no es recomendable usar formatos como JSON, porque hacen de cuello de botella.
 
Última edición:

Manurocker95

Doctorando en Ingeniería Biomédica & Game Dev
Miembro insignia
Para físicas (Rigidbody,Colliders... etc), es muy recomendable echar un ojo a:

 
Arriba