Estos son algunos consejos para nuevos programadores en videojuegos, si estas leyendo esto, espero que te ahorre un monton de lagrimas este blog. Creo que alguien más desconfiado que un programador no existe, tendemos a pensar que cualquier código hecho por otro es carente o está mal escrito, por eso hacemos herramientas alternativas dentro del mismo motor para que hagan exactamente lo mismo, entonces encontramos gente que hace sus animaciones a punta de código, sistemas de trazado de caminos para inteligencias artificiales alternativos, haciendo que el compilador demore un monton. No quiero que se me malinterprete, si ya has analizado que realmente necesitas un camino alternativo está bien, mi reflexión es a confiar más en el intelecto de otros para aprovechar esfuerzos en cosas necesarias.
Desactiva todo lo innecesario.
A veces es mejor no hacer nada en código que hacer que las cosas funcionen detrás del telón, cuando estaba desarrollando Dynamic Occlusion pasaba que tenia muchas cosas funcionando en tiempo real a pesar que ya había desactivado los componentes cuando lo mejor que podía hacer era desactivar todo el objeto y dejarlo inactivo hasta que entrara en escena. así mismo no necesito explicar los tips. aquí van algunos ejemplos.
desactiva la inteligencia artificial si esta se encuentra muy lejos.
desactiva las partículas si no están en pantalla.
desactiva los objetos que no estén cerca.
construya en juego pensando en occlusion culling en mente. etc.
Usa lenguajes fuertemente tipados.
Si por alguna razón necesitas pensar en un lenguaje concreto para desarrollar un juego o si el motor que elegiste te permite seleccionar entre varios lenguajes, opta por los que son más estrictos, los lenguajes que son flexibles para no declarar el tipo de variable, supone un esfuerzo más al procesador al tratar de adivinar el tipo de variable que se está usando. también invito a que los que usan C# eviten usar la palabra "var" en vez de usar directamente el tipo de variable, aparte que dificulta la legibilidad, también supone una carga al procesador.
Reduce los llamados innecesarios a funciones tanto como sea posible.
Reducir en lo posible todos los Callbacks o llamados a funciones y evitar los llamados vacíos, como funciones Update() vacías o cualquier otra que entra dentro del ciclo de vida de unity, no hay razón para tenerlas funcionando si están vacías, si las estás usando trata de reducir tanto como sea posible las órdenes si estas no son necesarias calcularlas en tiempo real y usa una corrutina en su caso.
Usa corrutinas más a menudo.
Hace poco tuve una discusión en la red acerca de este tema, para algunos este tema es polémico porque se dice que se pierde rendimiento al usar una corrutina y otros piensan que una corrutina corre en otro hilo del procesador, ambas afirmaciones son falsas, una corrutina es lo mismo que tener una función que se ejecuta periódicamente en el mismo hilo y en el mismo núcleo del procesador, solo que este detiene y reanuda su ejecución y por eso da la ilusión de estar funcionando en paralelo, esto es ideal para pasar codigo que haga comprobaciones constantes pero que no sea primordial que se ejecute a tiempo real con los ciclos del procesador, ejemplo:
como hacer un simple reloj digital que incremente segundo a segundo.
para el uso de stats en juegos donde no necesites inmediatez
para hacer uso de ciclos de día y noche que son de uso más cosmético.
para hacer cálculos que use el tiempo real en vez de usar cuadros por segundo.
para cargar assets o escenas en segundo plano
para bucles que necesitan ser comprobados o actualizados constantemente y que no necesites resultados inmediatos.
para hacer precache de archivos en memoria mientras se ejecuta el juego en tiempo real.
Uso de más núcleos en el procesador.
Unity no está diseñado de momento para aprovechar todos los núcleos del procesador, pero parece que pronto esto va a cambiar con Job system, sin embargo casi todo motor tiene dificultad a la hora de usar todos los núcleos del procesador son pocos y de hecho es casi imposible, los sistemas que andan corriendo código en paralelo está proporcionado por los mismos usuarios de manera experimental, la api de unity no corre en otros núcleos por ahora, así que los cálculos que hagas en otros núcleos no deben llamar a ninguna clase de la api de unity, te quedarás solo con las librerías de C#, por otra parte tienes que tener cuidado al recibir el resultado de lo que has calculado en ese otro hilo, la comunicación entre núcleos puede hacer que se pierda el cálculo, envíalo primero a la memoria para que el otro hilo sea capaz de recuperarlo, así que aquí hay algunos pocos ejemplos de en qué casos usar otro núcleo.
Si usas cálculos muy complejos de generación procedural ruido perlin
Generación de mallas usando el algoritmo de marching cubes.
Generación de texturas.
Generación de audio en crudo.
Algoritmos de búsqueda de caminos como A* o cualquier otro.
En general cualquier cosa aislada de la api de unity que necesite estar calculando constantemente y que pudiera significar un consumo considerable.
Usar más la tarjeta gráfica para hacer cálculos comunes.
Esta es una implementación relativamente nueva en unity distinta de solo graficos, para eso están los lenguajes GPGPU (General Purpose Graphic Processor Unit) y para eso está en unity los Compute shader, para ser usado para los mismos propósitos que usar un hilo aparte en el procesador.
Hay que tener algunas consideraciones en general si vas a usar más núcleos o la gráfica, es cierto que ganas rendimiento pero también lo pierdes al mandarle los cálculos a la memoria,
por otra parte usar más núcleos también aumenta las temperaturas del procesador, y en un dispositivo móvil, esto genera estrangulamiento térmico, lo que puede hacer que baje las frecuencias del reloj y encontrarte con bajadas de frames.
Trata de no crear generadores de cosas en dispositivos poco potentes, nada supera al código bien escrito, bien pensado, bien optimizado y a la austeridad.
Si estamos hablando del uso de núcleos o GPU para hacer cálculos extras, seria bueno que de vez en cuando compiles versiones previas de tu juego y lo pruebes usando MSI Afterburner o similares para tratar de equilibrar el consumo entre gráfica y procesador.
Hacer uso más intensivo de shaders.
Hay tareas comunes como animación de vértices, viento, proyectores o efectos de imagen y de partículas que al ser usados en procesador le suponen un esfuerzo mayor, para eso es mejor la gráfica, piensa que si hay algo que uses de forma cosmética en tu juego y se te da bien la programación de shaders, no dudes en hacer shaders para esas tareas.
Haz scripts modulares.
La tendencia a la hora de programar es pensar en usar un script para el comportamiento de cada objeto, pero este enfoque es incorrecto y redundante, la forma es pensando si es posible usar herencias y hacer pequeños scripts para pequeños comportamientos genéricos que puedan ser reutilizables una y otra vez, en el largo plazo esto hará que sea más fácil de corregir, genera menos redundancia, la compilación es mas rapida, hace tu proyecto más escalable y si por alguna razón el proyecto fracasa, puedes reutilizar la mayoría del código en futuros proyectos sin problema.
Usa las herramientas que te proporciona el mismo motor.
No está mal probar por experimentar la creación de una versión alternativa de alguna herramienta, quizás te sirva en un futuro para hacer tu propio motor, pero pensar hacerlo para suplantar la herramienta en sí, no es buena idea y menos en un proyecto serio, los inconvenientes son más que las ventajas, tienes que estar esclavo de las actualizaciones, esclavo de la edición del manual de uso, si la API de Unity cambia, tendrás que corregir errores.
Esto también aplica a assets de terceros, que también puede contener errores, el soporte no suele ser muy atento, pero hay assets que añaden características al motor y no tratan de suplantar nada, estas son muy recomendables siempre que goza de buena reputación.
Es mejor ser modesto y aprender a usar las herramientas que ofrece el motor con sus limitaciones y quizás mejorar alguna limitación con algún complemento, así tu esfuerzo se aprovecha para algo más necesario y el motor tendrá menos problemas para interpretar lo que ocurra dentro del juego.
Esto ha sido por ahora, espero que haya sido útil estos consejos basados en mi experiencia. Depende del proyecto que estés desarrollando, también es la complejidad de las herramientas. Nos vemos en el siguiente blog.
Comments