Los 10 errores más comunes que cometen los desarrolladores de Unity

Publicado: 2022-03-11

Unity es una herramienta excelente y sencilla de usar para el desarrollo multiplataforma. Sus principios son fáciles de entender y usted puede comenzar intuitivamente a crear sus productos. Sin embargo, si no se tienen en cuenta algunas cosas, se ralentizará su progreso cuando avance con su trabajo al siguiente nivel, a medida que avanza desde la fase de prototipo inicial o se acerca a una versión final. Este artículo brindará consejos sobre cómo superar los problemas más comunes y cómo evitar errores fundamentales en sus proyectos nuevos o existentes. Tenga en cuenta que la perspectiva de este artículo se centra más en el desarrollo de aplicaciones 3D, pero todo lo mencionado también se aplica al desarrollo 2D.

Unity es una herramienta excelente y sencilla de usar para el desarrollo multiplataforma.
Pío

Error común de Unity n.º 1: subestimar la fase de planificación del proyecto

Para cada proyecto, es crucial determinar varias cosas antes de que comience el diseño de la aplicación y la parte de programación del proyecto. En estos días, cuando el marketing de productos es una parte importante de todo el proceso, también es importante tener una idea clara de cuál será el modelo de negocio de la aplicación implementada. Debe estar seguro de para qué plataformas lanzará el producto y qué plataformas están en su plan. También es necesario establecer las especificaciones mínimas de los dispositivos admitidos (¿admite dispositivos de gama baja más antiguos o solo modelos más recientes?) para tener una idea del rendimiento y las imágenes que puede pagar. Cada tema en este artículo está influenciado por este hecho.

Desde un punto de vista más técnico, debería ser necesario establecer de antemano todo el flujo de trabajo de creación de activos y modelos mientras se los proporciona al programador, con especial atención al proceso de iteración cuando los modelos necesitarán más cambios y mejoras. Debe tener una idea clara sobre la velocidad de fotogramas deseada y el presupuesto de vértices, de modo que el artista 3D pueda saber en qué resolución máxima deben estar los modelos y cuántas variaciones de LOD debe hacer. También se debe especificar cómo unificar todas las medidas para tener una escala consistente y un proceso de importación a lo largo de toda la aplicación.

La forma en que se diseñarán los niveles es crucial para el trabajo futuro porque la división del nivel influye mucho en el rendimiento. Siempre debes tener en cuenta las preocupaciones sobre el rendimiento cuando diseñes nuevos niveles. No vayas con visiones poco realistas. Siempre es importante hacerse la pregunta "¿se puede lograr razonablemente?" Si no es así, no deberías desperdiciar tus valiosos recursos en algo difícilmente alcanzable (en caso de que no sea parte de tu estrategia comercial tenerlo como tu principal ventaja competitiva, por supuesto).

Error común de Unity n.º 2: trabajar con modelos no optimizados

Es fundamental tener todos tus modelos bien preparados para poder usarlos en tus escenas sin más modificaciones. Hay varias cosas que el buen modelo debe cumplir.

Es importante configurar la escala correctamente. A veces no es posible configurarlo correctamente desde su software de modelado 3D debido a las diferentes unidades que utilizan estas aplicaciones. Para hacer todo bien, configure el factor de escala en la configuración de importación de modelos (deje 0.01 para 3dsMax y Modo, configure 1.0 para Maya) y tenga en cuenta que a veces necesitará volver a importar objetos después de cambiar la configuración de escala. Estas configuraciones deberían asegurar que puede usar solo la escala básica 1,1,1 en sus escenas para obtener un comportamiento consistente y sin problemas de física. El procesamiento por lotes dinámico también funcionará correctamente. Esta regla también debe aplicarse a todos los subobjetos del modelo, no solo al principal. Cuando necesite ajustar las dimensiones de los objetos, hágalo con respecto a otros objetos en la aplicación de modelado 3D en lugar de en Unity. Sin embargo, puede experimentar con la escala en Unity para encontrar los valores apropiados, pero para la aplicación final y el flujo de trabajo consistente, es bueno tener todo bien preparado antes de importar a Unity.

Con respecto a la funcionalidad del objeto y sus partes dinámicas, tenga sus modelos bien divididos. Cuantos menos subobjetos, mejor. Separe las partes del objeto en caso de que las necesite, por ejemplo, para mover o rotar dinámicamente, con fines de animación u otras interacciones. Cada objeto y sus subobjetos deben tener su pivote correctamente alineado y rotado con respecto a su función principal. El objeto principal debe tener el eje Z apuntando hacia adelante y el pivote debe estar en la parte inferior del objeto para una mejor ubicación en la escena. Use la menor cantidad posible de materiales en los objetos (más sobre esto a continuación).

Todos los activos deben tener nombres propios que describan fácilmente su tipo y funcionalidad. Mantenga esta consistencia en todos sus proyectos.

Error común de Unity n.º 3: crear una arquitectura de código interdependiente

La creación de prototipos y la implementación de la funcionalidad en Unity es bastante fácil. Puede arrastrar y soltar fácilmente cualquier referencia a otros objetos, dirigirse a cada uno de los objetos de la escena y acceder a todos los componentes que tiene. Sin embargo, esto también puede ser potencialmente peligroso. Además de los problemas de rendimiento notables (encontrar un objeto en la jerarquía y el acceso a los componentes tiene su sobrecarga), también existe un gran peligro al hacer que partes de su código dependan completamente entre sí. O depender de otros sistemas y scripts exclusivos de su aplicación, o incluso de la escena actual o el escenario actual. Intente adoptar un enfoque más modular y cree piezas reutilizables que puedan usarse en otras partes de su aplicación, o incluso compartirse en toda su cartera de aplicaciones. Cree su marco y bibliotecas sobre la API de Unity de la misma manera que está construyendo su base de conocimientos.

Hay muchos enfoques diferentes para asegurar esto. Un buen punto de partida es el propio sistema de componentes de Unity. Pueden aparecer complicaciones cuando determinados componentes necesitan comunicarse con otros sistemas de la aplicación. Para esto, puede usar interfaces para hacer que partes de su sistema sean más abstractas y reutilizables. Alternativamente, puede utilizar un enfoque basado en eventos para reaccionar ante eventos particulares desde fuera del alcance, ya sea creando un sistema de mensajería o registrándose directamente en partes del otro sistema como oyentes. El enfoque correcto será tratar de separar las propiedades de gameObject de la lógica del programa (al menos algo así como el principio del modelo-controlador), porque es difícil identificar qué objetos están modificando sus propiedades de transformación, como la posición y la rotación. Debe ser responsabilidad exclusiva de su responsable.

Intenta que todo esté bien documentado. Trátelo siempre como si regresara a su código después de mucho tiempo y necesita comprender rápidamente qué está haciendo exactamente esta parte del código. Porque en realidad, muy a menudo llegará a algunas partes de su aplicación después de un tiempo y es un obstáculo innecesario para saltar rápidamente al problema. Pero no se exceda en esto. A veces, un nombre apropiado de clase, método o propiedad es suficiente.

Error común de Unity n.º 4: desperdiciar tu rendimiento

La última línea de productos de teléfonos móviles, consolas o computadoras de escritorio nunca será tan avanzada como para no tener que preocuparse por el rendimiento. Las optimizaciones de rendimiento siempre son necesarias y proporcionan la base para marcar la diferencia en el aspecto de su juego o aplicación en comparación con otros en el mercado. Porque cuando guarda algo de rendimiento en una parte, puede usarlo para pulir otras partes de su aplicación.

Hay muchas áreas para optimizaciones. Se necesitaría todo el artículo solo para rascar la superficie sobre este tema. Al menos, intentaré dividir este dominio en algunas áreas centrales.

Actualizar bucles

No use cosas de rendimiento intensivo en los bucles de actualización, use el almacenamiento en caché en su lugar. Un ejemplo típico es el acceso a componentes u otros objetos en una escena o cálculos intensivos en sus guiones. Si es posible, almacene en caché todo en los métodos Awake() , o cambie su arquitectura a un enfoque más basado en eventos para activar las cosas justo cuando se necesitan.

instanciaciones

Para los objetos que se instancian con bastante frecuencia (por ejemplo, balas en un juego FPS), haga un grupo preinicializado de ellos y simplemente elija uno ya inicializado cuando lo necesite y actívelo. Luego, en lugar de destruirlo cuando ya no sea necesario, desactívalo y devuélvelo a la piscina.

Representación

Utilice técnicas de selección de oclusión o LOD para limitar las partes renderizadas de la escena. Intente utilizar modelos optimizados para poder mantener bajo control el recuento de vértices en la escena. Tenga en cuenta que el recuento de vértices no es solo el número de vértices en el modelo en sí, sino que está influenciado por otras cosas como las normales (bordes duros), las coordenadas UV (costuras UV) y los colores de los vértices. Además, una cantidad de luces dinámicas en la escena influirán dramáticamente en el rendimiento general, así que trate de hornear todo con anticipación siempre que sea posible.

Dibujar llamadas

Trate de reducir el número de llamadas de empate. En Unity, puede lograr la reducción de las llamadas dibujadas mediante el uso de procesamiento por lotes estático para objetos estáticos y procesamiento por lotes dinámico para objetos en movimiento. Sin embargo, primero debe preparar sus escenas y modelos (los objetos por lotes deben compartir los mismos materiales), y el procesamiento por lotes de objetos dinámicos solo funciona para modelos de baja resolución. Alternativamente, puede combinar mallas por el script en una sola ( Mesh.CombineMeshes ) en lugar de usar el procesamiento por lotes, pero debe tener cuidado de no crear objetos demasiado grandes que no puedan aprovechar la selección de vistas frustum en algunas plataformas. En general, la clave es usar la menor cantidad de materiales posible y compartirlos en la escena. A veces necesitará crear atlas a partir de texturas para poder compartir un material entre distintos objetos. Un buen consejo es también usar una resolución más alta de las texturas de los mapas de luz de la escena (no la resolución generada, sino la resolución de salida de la textura) para reducir su número cuando esté horneando luz en entornos más grandes.

Problemas de sobregiro

No use texturas transparentes cuando no sea necesario, ya que causará problemas de tasa de relleno. Está bien usarlo para geometría complicada y más distante, como árboles o arbustos. Cuando necesite usarlo, prefiera sombreadores combinados alfa en lugar de sombreadores con pruebas alfa o en lugar de sombreadores recortados para plataformas móviles. Para identificar estos problemas en general, intente reducir la resolución de su aplicación. Si ayuda, es posible que tenga estos problemas de tasa de llenado o que necesite optimizar más sus sombreadores. De lo contrario, puede ser más un problema de memoria.

sombreadores

Optimice sus sombreadores para un mejor rendimiento. Reduzca el número de pasadas, use variables con menor precisión, reemplace cálculos matemáticos complicados con texturas de búsqueda generadas previamente.

Utilice siempre un perfilador para determinar los cuellos de botella. Es una gran herramienta. Para el renderizado, también puede usar el asombroso Frame Debugger, que lo ayudará a aprender mucho sobre cómo funcionan las cosas en general al descomponer los procesos de renderizado con él.

Error común de Unity n.º 5: ignorar los problemas de recolección de elementos no utilizados

Es necesario darse cuenta de que a pesar de que Garbage Collector (GC) en sí mismo nos ayuda a ser realmente eficientes y enfocados en cosas importantes en la programación, hay algunas cosas que debemos tener en cuenta explícitamente. El uso de GC no es gratuito. En general, debemos evitar las asignaciones de memoria innecesarias para evitar que GC se dispare con demasiada frecuencia y, por lo tanto, arruine el rendimiento debido a los picos de velocidad de fotogramas. Idealmente, no debería haber nuevas asignaciones de memoria que ocurran regularmente en cada cuadro. Sin embargo, ¿cómo podemos lograr este objetivo? Realmente está determinado por la arquitectura de la aplicación, pero hay algunas reglas que puede seguir que ayudan:

  • Evite asignaciones innecesarias en bucles de actualización.
  • Use estructuras para contenedores de propiedades simples, ya que no están asignados en el montón.
  • Intente preasignar arreglos o listas u otras colecciones de objetos, en lugar de crearlos dentro de los bucles de actualización.
  • Evite usar cosas mono problemáticas (como expresiones LINQ o bucles foreach, por ejemplo) porque Unity está usando una versión anterior, no idealmente optimizada de Mono (en el momento de escribir este artículo, es la versión 2.6 modificada, con una actualización en la hoja de ruta).
  • Cadenas de caché en métodos Awake() o en eventos.
  • Si es necesaria la actualización de la propiedad de cadena en el bucle de actualización, use el objeto StringBuilder en lugar de la cadena.
  • Utilice el generador de perfiles para identificar problemas potenciales.

Error común de Unity n.º 6: optimizar el uso de la memoria y el espacio al final

Es necesario mantener la atención en el menor uso de memoria y espacio de la aplicación desde el inicio del proyecto, ya que es más complicado hacerlo cuando se deja la optimización para la fase de prelanzamiento. En los dispositivos móviles, esto es aún más importante, porque estamos bastante cortos de recursos allí. Además, al superar los 100 MB de tamaño de la instalación, podemos perder una cantidad importante de nuestros clientes. Esto se debe al límite de 100 MB para las descargas de la red celular y también a razones psicológicas. Siempre es mejor cuando su aplicación no desperdicia los valiosos recursos del teléfono del cliente, y es más probable que descarguen o compren su aplicación cuando su tamaño es más pequeño.

Para encontrar agotadores de recursos, puede usar el registro del editor donde puede ver (después de cada nueva compilación) el tamaño de los recursos divididos en categorías separadas, como audio, texturas y archivos DLL. Para una mejor orientación, hay extensiones de editor en Unity Asset Store, que le proporcionarán un resumen detallado con recursos y archivos a los que se hace referencia en su sistema de archivos. El consumo de memoria real también se puede ver en el generador de perfiles, pero se recomienda probarlo cuando se conecta para construir en su plataforma de destino porque hay muchas inconsistencias cuando se prueba en un editor o en cualquier otra plataforma que no sea su destino.

Los mayores consumidores de memoria suelen ser las texturas. Preferiblemente, use texturas comprimidas ya que ocupan mucho menos espacio y memoria. Cuadre todas las texturas, idealmente, haga que la longitud de ambos lados sea potencia de dos (POT), pero tenga en cuenta que Unity también puede escalar texturas NPOT a POT automáticamente. Las texturas se pueden comprimir cuando están en forma de POT. Atlas texturiza juntas para llenar toda la textura. A veces, incluso puede usar el canal alfa de textura para obtener información adicional para sus sombreadores para ahorrar espacio y rendimiento adicionales. Y, por supuesto, trate de reutilizar texturas para sus escenas tanto como sea posible y use texturas repetitivas cuando sea posible conservar una buena apariencia visual. Para dispositivos de gama baja, puede reducir la resolución de las texturas en Configuración de calidad. Utilice el formato de audio comprimido para clips de audio más largos, como la música de fondo.

Cuando se trata de diferentes plataformas, resoluciones o localizaciones, puede usar paquetes de activos para usar diferentes conjuntos de texturas para diferentes dispositivos o usuarios. Estos paquetes de activos se pueden cargar dinámicamente desde Internet después de instalar la aplicación. De esta forma, puedes superar el límite de 100 MB descargando recursos durante el juego.

Error común de Unity #7: Errores comunes de física

A veces, cuando movemos objetos en la escena, no nos damos cuenta de que el objeto tiene un colisionador y que cambiar su posición obligará al motor a recalcular todo el mundo físico de nuevo. En ese caso, debe agregarle el componente Rigidbody (puede configurarlo en no cinemático si no desea que se involucren fuerzas externas).

Para modificar la posición del objeto con Rigidbody sobre él, establezca siempre Rigidbody.position cuando una nueva posición no sigue a la anterior, o Rigidbody.MovePosition cuando se trata de un movimiento continuo, que también tiene en cuenta la interpolación. Al modificarlo aplicar operaciones siempre en FixedUpdate , no en funciones Update . Asegurará comportamientos físicos consistentes.

Si es posible, use colisionadores primitivos en gameObjects, como esfera, caja o cilindro, y no colisionadores de malla. Puede componer su colisionador final a partir de más de uno de estos colisionadores. La física puede ser un cuello de botella en el rendimiento de su aplicación debido a la sobrecarga de la CPU y las colisiones entre colisionadores primitivos son mucho más rápidas de calcular. También puede ajustar la configuración de intervalo de tiempo fijo en el Administrador de tiempo para reducir la frecuencia de las actualizaciones fijas de física cuando la precisión de la interacción física no es tan necesaria.

Error común de Unity n.º 8: Probar manualmente todas las funciones

A veces puede haber una tendencia a probar la funcionalidad manualmente experimentando en el modo de juego porque es bastante divertido y tienes todo bajo tu control directo. Pero este factor genial puede disminuir con bastante rapidez. Cuanto más compleja se vuelve la aplicación, más tareas tediosas tiene que repetir el programador y pensar en ellas para asegurarse de que la aplicación se comporte como se pretendía originalmente. Fácilmente puede convertirse en la peor parte de todo el proceso de desarrollo, debido a su carácter repetitivo y pasivo. Además, debido a que la repetición manual de los escenarios de prueba no es tan divertida, existe una mayor probabilidad de que algunos errores superen todo el proceso de prueba.

Unity tiene excelentes herramientas de prueba para automatizar esto. Con un diseño arquitectónico y de código apropiado, puede usar pruebas unitarias para probar funcionalidades aisladas, o incluso pruebas de integración para probar escenarios más complejos. Puede reducir drásticamente el enfoque de prueba y verificación en el que está registrando datos reales y comparándolos con su estado deseado.

Las pruebas manuales son sin duda una parte crítica del desarrollo. Pero su cantidad se puede reducir y todo el proceso puede ser más robusto y rápido. Cuando no haya una forma posible de automatizarlo, prepare sus escenas de prueba para poder abordar el problema que está tratando de resolver lo más rápido posible. Idealmente, unos pocos fotogramas después de presionar el botón de reproducción. Implemente atajos o trucos para establecer el estado deseado para la prueba. Además, aísle la situación de la prueba para asegurarse de qué está causando el problema. Cada segundo innecesario en el modo de reproducción cuando se acumulan las pruebas, y cuanto mayor sea el sesgo inicial de probar el problema, más probable es que no pruebe el problema en absoluto, y esperará que todo funcione bien. Pero probablemente no lo hará.

Error común de Unity n.° 9: Pensar que los complementos de la tienda de activos de Unity resolverán todos sus problemas

Confía en mí; no lo harán Cuando trabajaba con algunos clientes, a veces me enfrentaba a la tendencia o las reliquias del pasado de usar complementos de la tienda de activos para cada pequeña cosa. No quiero decir que no haya extensiones útiles de Unity en la tienda de recursos de Unity. Hay muchos de ellos y, a veces, incluso es difícil decidir cuál elegir. Pero para cada proyecto, es importante mantener la coherencia, que puede ser destruida por el uso imprudente de diferentes piezas que no encajan bien entre sí.

Por otro lado, para la funcionalidad que le llevaría mucho tiempo implementar, siempre es útil usar productos bien probados de Unity Asset Store, que pueden ahorrarle una gran cantidad de tiempo de desarrollo. Sin embargo, elija con cuidado, use los probados que no traerán muchos errores incontrolables y extraños a su producto final. Las reseñas de cinco estrellas son una buena medida para empezar.

Si la funcionalidad que desea no es difícil de implementar, simplemente agréguela a sus bibliotecas personales (o de la empresa) en constante crecimiento, que se pueden usar en todos sus proyectos más adelante. De esa manera, está mejorando su conocimiento y su conjunto de herramientas al mismo tiempo.

Error común de Unity n.º 10: no tener necesidad de ampliar la funcionalidad básica de Unity

A veces puede parecer que el entorno de Unity Editor es suficiente para las pruebas básicas del juego y el diseño de niveles, y ampliarlo es una pérdida de tiempo. Pero créeme, no lo es. El gran potencial de extensión de Unity proviene de poder adaptarlo a problemas específicos que necesitan ser resueltos en varios proyectos. Esto puede mejorar la experiencia del usuario cuando trabaja en Unity o acelerar drásticamente todo el flujo de trabajo de desarrollo y diseño de niveles. Sería desafortunado no utilizar las funciones integradas, como los cajones de propiedades integrados o personalizados, los cajones de decoración, la configuración personalizada del inspector de componentes, o incluso no crear complementos completos con su propio editor de ventanas.

Conclusión

Espero que estos temas te sean útiles a medida que avanzas en tus proyectos de Unity. Hay muchas cosas que son específicas del proyecto, por lo que no se pueden aplicar, pero siempre es útil tener algunas reglas básicas en mente cuando se trata de resolver problemas más difíciles y específicos. Es posible que tenga diferentes opiniones o procedimientos sobre cómo resolver estos problemas en sus proyectos. Lo más importante es mantener sus modismos consistentes a lo largo de su proyecto para que cualquier miembro de su equipo pueda entender claramente cómo debería haberse resuelto correctamente el dominio en particular.


Lecturas adicionales en el blog de ingeniería de Toptal:

  • Unity AI Development: un tutorial de máquina de estado finito