Hacer juegos no es difícil. Mirando hacia atrás en un pequeño proyecto móvil en Unity3D

Cuando tengas una idea de una nueva mecánica de juego, o incluso un destello de un concepto interesante, pronto estarás obsesionado con esto con una inmensa necesidad de comenzar a hacer algo. A veces escribes tales ideas en alguna parte y les das la oportunidad de encender el ciclo de desarrollo completo más adelante. Pero me he topado con la acción opuesta. Mi juego actual se convirtió en este monstruo gigante comiendo finanzas y tiempo, y se hizo mucho más grande de lo que nunca pensé. Entonces, tuve que volver a ponerlo por un tiempo. ¡Pero no podría sentarme sin el desarrollo del juego, y en mi tiempo libre comencé a trabajar en mi nuevo proyecto! Además, ese era bastante diferente de los anteriores, porque he decidido apuntar a dispositivos móviles. Si está interesado en cómo se realizó este proyecto, desde una pequeña idea hasta el lanzamiento final, ¡vamos a sumergirnos en él!



Claramente, estoy contando sobre mi experiencia y mi visión, pero muchas cosas serían comunes para cualquier proyecto, y tal vez encuentre algunos consejos útiles para usted.

Esculpiendo sobre la base de la idea


La idea principal era bastante simple: ¡hagamos un laberinto, un laberinto! Aunque puedes encontrar algunos juegos simples en ese género en la tienda, pero creo que deberías traer algo más al juego que solo seguir el cliché de género. Tengo una profunda preocupación por el diseño de juegos en general, me encantan las historias y las experiencias de aventuras completas con un comienzo distinto y un final destacado. No podría hacer aquí una excepción a mis ideales. Además, quería una mecánica de juego interesante. Mi enfoque fue agregar otra variable a todo el concepto de escapar del laberinto. Y después de una lluvia de ideas, nació la nueva idea. Esa era la cadena y el sistema de interruptores de cadena. Entonces, el movimiento del personaje principal está restringido por la longitud de la cadena y los caminos que el jugador eligió. Con eso en mente, ¡no solo necesitarás encontrar la salida, sino encontrar el camino más corto posible! Y qué pasa si te digo que tu cadena es bastante corta y puedes ir más allá solo después de un interruptor de cadena que proporcionará el nuevo punto de anclaje y la nueva cadena con una longitud diferente. Ahora, el juego comienza a ser más difícil, porque necesitarás encontrar el orden correcto de esos interruptores dentro del laberinto. Y si eso no fuera suficiente para usted, entonces agreguemos puertas, que necesita abrir con activadores especiales en algún lugar dentro de un laberinto y luego regresar aún pensando en los interruptores y la cadena.



Entendiendo los límites


Ciertamente, no fue fácil planificar todas esas características con anticipación. Algunos de ellos se hicieron debido a limitaciones técnicas y estricta gestión del tiempo. El propósito era hacerlo lo más rápido posible y no aumentar dramáticamente la complejidad de todos los aspectos del juego en el proceso de desarrollo. La cadena se hizo usando las uniones, y no pudo ser procesada por la física del motor del juego después de cierta longitud, literalmente estallando en pedazos. Así que he necesitado restringir su longitud y aún así poder continuar el camino. De hecho, había una solución para escribir scripts de cadena totalmente personalizados que fingían la física real, pero esa era una tarea que consumía mucho tiempo y que no podía permitirme.
Aún así, me las arreglé para mantener un poco la longitud de la cadena, y el pensamiento inicial fue hacer pequeñas cámaras de laberinto donde necesita encontrar el camino más corto, pero eso no fue suficiente. Si todo el juego fuera así, sería bastante tedioso porque solo tienes una tarea repetitiva sin cambiar la experiencia, o incluso la dificultad. Aún así, esas ideas jugaron un papel en el juego final.

Inspiración y pensamientos: experiencia en prototipos


Después de algunos prototipos, quedó claro que los laberintos, donde tienes que desviarte de la ruta más corta e incluso tener algún retroceso, fueron los más interesantes. Entonces, la decisión final fue agregar secciones de juego separadas una tras otra: los grandes laberintos con múltiples interruptores y pequeños laberintos con la forma más corta posible. Todos ellos se conectaron con algunos pasillos vacíos para liberar la mente del jugador de la sensación de desafío constante. Pero justo en el momento de las pruebas surgió otra idea que proporcionó un nuevo pensamiento crítico: necesitamos más mecánica de juego. Porque estar en las mismas paredes de estos laberintos uno tras otro, incluso con alguna curva de dificultad, todavía no era suficiente para mantener la atención de los jugadores.

Para sumarse a la capacidad de atención, no olvide que el juego está dirigido a la plataforma móvil. Nunca lo diseñes para tener largas sesiones de juego sin descanso. He decidido guardar en cada cambio de cadena, para que el jugador pueda irse en cualquier momento y nunca estar lejos de la sesión de juego anterior. Por supuesto, tengo algunas intenciones de cómo se debe jugar el juego, pero mi sesión ininterrumpida máxima prevista es de aproximadamente 5 minutos. Eso solo incluye escenas donde se presenta la música.

Volviendo a la variedad mecánica, he agregado rompecabezas que involucran la cadena como la herramienta para resolverlos. Es una excelente solución de diseño de juegos: reutilizar objetos del mundo con los que ya está familiarizado como la nueva herramienta de propósito.



Hubo varias ideas de muchos rompecabezas diferentes con esta nueva herramienta, pero la decisión final fue implementar solo un tipo con variación en su dificultad. Si crees que tu juego necesita todas tus nuevas ideas y sus variaciones, pero no tienes tiempo para implementarlas, ¡detente! Tu objetivo aquí es terminar el juego. En el caso, no implementará esas características ahora, o incluso hasta el final del ciclo de desarrollo, la única solución es actualizar el juego más tarde, y la segunda y más radical, para hacer un juego completamente nuevo más tarde con todo lo que falta características. Si tienes el producto principal en tu mano, entonces sería más fácil continuar. Simplemente no permita que las funciones detengan el lanzamiento. Hágalo solo si son la parte crítica del producto completo que le agrega una experiencia única y no puede imaginar el juego sin esas características.

Eche un vistazo a las cosas técnicas: cómo se construyó el mundo


La cadena se hizo con juntas configurables con movimiento bloqueado en todos los ejes. Luego se instancia como segmentos de cadena, con 4 cuerpos rígidos conectados entre sí por 4 articulaciones en un segmento. Las fuentes de la cadena son similares a los pozos. Para un funcionamiento adecuado, simplemente eliminé segmentos que iban debajo de la superficie e hice una instancia de otros nuevos cuando la última articulación del segmento se acercó a la superficie. Además, el cuerpo rígido de la última articulación estaba restringido para tener movimiento vertical solo para mantenerse como el ancla. Además, la cuerda tiene un material de colisión especial sin mucha fricción.



El jugador se hizo con un cuerpo rígido que tiene un guión simple de seguir al objetivo para moverlo. Y el objetivo tiene un agente de navegación. Entonces, cuando movemos nuestro joystick, movemos el objetivo solo con el sistema de navegación, y el cuerpo rígido del jugador intentó alcanzar el objetivo por la fuerza física. Si tuviéramos solo el sistema de navegación, entonces la cadena no podría detenerlo, y el jugador actuó como el cuerpo rígido cinemático con control absoluto de posición. El único problema con la aplicación de fuerza es que con el recuento variable de segmentos de cadena, también tenemos la variable en masa adjunta al jugador. Luego, si tiene demasiada masa en el límite final de la cadena, explotará. Y de lo contrario, el jugador sería arrastrado hacia atrás por la cadena o no se movería en absoluto. Así que apliqué un cambio en la masa en relación con la longitud real de la cadena. Pero la solución más interesante contra la explosión de la cadena, la desestabilización de su física, fue limitar la velocidad máxima en sus partes singulares mediante un script personalizado.

El Laberinto en sí estaba hecho de laberintos, rompecabezas y pasillos más pequeños que los conectaban a todos. Cuando comencé a diseñar esos laberintos, simplemente tomé mi bolígrafo y papel cuadrado y comencé a dibujarlos pared por pared. Pero después de numerosos cambios debido a la creación de prototipos reales, y cómo fue afectada por la cadena, estaba seguro de que era la forma más ineficaz de hacer las cosas. Entonces, hice una ventana de editor personalizada para mis laberintos. Era igual que el bolígrafo y el papel, pero con un estado guardado que podía generar el laberinto completo de paredes, pisos y prefabricados de fuentes en cadena. También agregué control sobre la longitud de las fuentes de la cadena, y fue la solución completa al problema del diseño del laberinto.



Solo tenga en cuenta que para la creación de instancias de tiempo del editor, debe usar métodos PrefabUtility y no la instanciación común porque, de lo contrario, obtendrá clones de sus objetos prefabricados separados del prefab original.

Post procesamiento


Es una preferencia personal, pero me encanta el procesamiento posterior y no podría imaginar mi juego sin él. Bloom es una opción imprescindible, pero también me gusta la profundidad de campo y la sencilla solución FXAA . Con la nueva pila de procesamiento posterior, los pasos para implementarla correctamente fueron bastante simples. También agregué una esfera de activación sobre el jugador, que tenía otro perfil con el efecto de aberración cromática , que se movió al jugador en el momento del cambio. Además, el perfil separado para la cinemática final. Pero después de una de las actualizaciones, todo dejó de funcionar , y después de probar en el dispositivo, me topé con otro problema . Con un poco de RenderDoc , el motivo fue claro e inmediatamente solucionado, pero espero que veamos la solución oficial del equipo de Unity.

Comienzo del camino de optimizaciones


Cuando el juego estaba casi listo, y el juego inicial en mi dispositivo había terminado, traté de lanzar el juego en un dispositivo no tan potente que tenía antes en el desarrollo. Eso fue patético. He notado pequeñas caídas en mi dispositivo antes, pero después de los pasos iniciales para resolver el problema de sobrecalentamiento, pensé que nunca vería un tartamudeo tan dramático.

Para el sobrecalentamiento: los pasos son sencillos, no necesitaba 60 fps, así que lo bloqueé a 30. Más un escalador de resolución personalizado que limitó el tamaño de la pantalla corta a 720p. Otro truco con cambiar los pasos de tiempo en Time Manager no funcionó para mí, debido a la gran dependencia de los cálculos pesados ​​de física. Cuando intenté aumentar el intervalo de tiempo, la cadena explotó con bastante frecuencia llegando a sus límites.

Todo ese trabajo se realizó antes de la prueba del dispositivo débil. Así que comencé a mirar más de cerca en el perfilador.

Un punto interesante fue que tenía demasiadas fuentes de audio que estaban habilitadas todo el tiempo. Pero nunca los necesité todos simultáneamente, y los eventos de jugarlos fueron bastante deterministas. Terminé con casi todas las fuentes deshabilitadas de forma predeterminada, y habilitándolas solo para la activación de sonido necesaria y luego deshabilitándolas justo después del final del sonido.

Algunas secuencias de comandos se beneficiaron de las actualizaciones manuales en lugar de las propietarias, especialmente cuando tenía muchos objetos similares con la misma secuencia de comandos y un método de actualización dentro de ellos. Simplemente cambie el nombre de su método de Actualización a ManualUpdate y llámelo desde afuera. En mi caso, todos mis acertijos estaban en la escena, y llamaron a sus métodos de actualización, también cada pilar dentro de cada rompecabezas tenía su propio método de actualización, e incluso los disparadores del pilar tenían sus propios métodos de actualización. Sin esas múltiples actualizaciones automáticas y el método de actualización de llamadas manualmente en cada objeto desde un solo lugar, he logrado reducir significativamente la sobrecarga de las llamadas a métodos internos de Unity.

La última pero una de las cosas más importantes dentro de la optimización es la parte de renderizado. Si quieres enviar tu juego móvil con sombreadores estándar , ¡estás loco! Tal vez, en algunos casos raros, con recuento de materiales pequeños y complejidad de variantes de sombreador pequeño, debido a que el sombreador estándar tiene toneladas de ellos, puede lograrlo mientras apunta solo a dispositivos de nivel superior. Pero en mi caso, terminé con casi todos los sombreadores cambiados para usar los personalizados, basados ​​en variantes de superficie móvil. Pero no he encontrado una buena manera de simular metal / suavidad con un modelo de iluminación personalizado, por lo que solo los materiales metálicos brillantes terminaron con el sombreador estándar. Sin embargo, si ve las versiones compiladas, no es obvio elegir la correcta cuando tiene más de 190 operaciones en el sombreador estándar frente a menos de 70 en una personalizada. Recuerde que el enfoque PBR , que incluye el sombreador estándar predeterminado, es realmente intensivo en GPU y demasiado complejo para dispositivos móviles. Debe usar sombreadores específicamente optimizados para dispositivos móviles desde el comienzo del desarrollo. Hágalos usted mismo o use los que están integrados en Unity.

La siguiente parada: depurador de tramas


El siguiente consejo de rendimiento es verificar el depurador de tramas para detectar interrupciones por lotes inusuales. O simplemente para ver cuántas llamadas de llamada necesita para representar toda la escena.

Tuve un comportamiento extraño cuando el depurador reveló que algunos objetos renderizados rompen secuencialmente el lote a pesar de tener el mismo material. Incluso el mensaje no estaba claro porque decía que tengo diferentes fuentes de luz para ellos. ¡Pero toda la escena utilizó la única fuente de luz direccional! ¡Esos objetos tenían el mismo material, y todas sus propiedades eran las mismas! Pero no todos porque estaba mirando solo el material y las propiedades de representación. La verdadera razón fue que cambié mi fuente de luz a una selección personalizada por capas. Y el objeto de secuencia de ruptura estaba en una capa específica que simplemente no estaba iluminada.

De todos modos, a veces el depurador de cuadros muestra un extraño orden de renderizado que rompe el procesamiento por lotes. Algunos de esos sucesos fueron ridículos, y la corrección manual de la cola de renderizado del material ayudó a resolverlo.

Además, el depurador de cuadros demostró que a pesar de tener casi todos los objetos renderizados como estáticos, tenía muchos lotes que no tenían ningún sentido. Solo porque tenía tantos, que el dosificador hizo muchas mallas estáticas por lotes, y nunca trató de agruparlas por posición. En ese caso, tenía mis paredes de laberinto en una pantalla compuesta de 5 o 6 lotes diferentes. ¡Pero aquellos hechos del mismo material! Terminé agregando solo objetos de piso como estáticos porque todos lo hicieron dentro de una malla por lotes. Y el resto se quedó con las paredes agrupadas dinámicamente sin ningún problema, con su cola de material corregida a una única. El procesamiento por lotes dinámico tiene cierto impacto en la CPU , pero en mi caso, la diferencia incluso en el dispositivo débil fue marginal en comparación con el procesamiento por lotes estático personalizado a través de StaticBatchingUtility . Y el procesamiento por lotes dinámico fue aún más efectivo para mí al guardar llamadas de extracción que una estática personalizada en los casos extremos.

Las otras cosas que señaló el depurador de cuadros fueron las sombras y las cascadas. Si tiene curiosidad, cada cascada de sombras es prácticamente otro paso de sombras para toda la pantalla. Entonces, si tiene varios lotes dentro de shadowpass, multiplique ese número por el número de cascadas que tiene. Acabo de deshabilitar las cascadas después de este descubrimiento. Pero aún necesitaba sombras decentes en tiempo real y terminé ajustando la distancia de recorte de la cámara y cambiando a las sombras ajustadas de calidad media. Sé que no son los más bonitos, pero fue mucho mejor que tener unos estables con una resolución inferior o ninguna sombra.

El último depurador y rendimiento del marco interno es el procesamiento posterior. Incluso con solo un par de efectos habilitados, esos fueron casi los más pesados: Bloom y Depth of Field. Ambos utilizaron el muestreo del marco a baja resolución pero con diferentes texturas de entrada y diferentes sombreadores de filtro. Ya había cambiado Bloom para usar el modo rápido: filtro cuadrado dentro del sombreador en lugar de circular más complejo. Lamentablemente eso no fue suficiente. Así que terminé cambiando el factor de escala de resolución dentro del búfer de cuadro inicial del efecto. Está usando la mitad de la resolución por defecto, pero he visto grandes mejoras cuando se usa no la mitad de la resolución, sino solo un tercio de ella. Reducirlo más de un cuarto casi no tuvo efecto con más efectos visuales degradantes. ¡Entonces mi solución para el procesamiento posterior en dispositivos móviles es un tercio! O utilizando soluciones completamente personalizadas.

Casi allí: polaco!


Naturalmente, cada proyecto es único, y debe pensar en el suyo en particular, pero aquí solo quería mostrar qué partes he decidido poner en mi proceso de pulido y por qué.
Los primeros pasos de pulido se realizaron justo después de la primera prueba alfa y antes de las optimizaciones de rendimiento. Con los comentarios iniciales, he agregado características menores que casi estaban allí, pero que no se han destacado del todo.

El primero fue el piso de color, que tuve una visión desde el comienzo del desarrollo, pero en el proceso real, todas las paletas que se me ocurrieron parecían poco naturales. Entonces, en la primera ronda, terminé con el gradiente de color de brillante a oscuro durante todo el camino del juego. Pero la prueba mostró que esto no era suficiente. Con un poco de lucha por todas las combinaciones de colores, se creó la correcta. Incluso este pequeño detalle visual tuvo un impacto notable en la sensación general del juego. Con la distinción entre etapas, tenías más sentido de logro y progreso.

La otra noción era la necesidad de tener una sensación más divertida y dinámica del jugador. Aunque al principio no era un fanático de él, logré encontrar un pequeño compromiso que se sintió mejor, pero que no modificó la sensación de calma del personaje. Ese fue el bloqueo del cristal dentro del jugador para que nunca girara relativamente al mundo. Pero para el jugador que sentía que el cristal interior giraba en cada movimiento. En realidad, cuando era solo un niño, tuve una pelota que tenía otra dentro. Esa parte interna flotaba en una pequeña cantidad de sustancia líquida que no se notaba, y cuando la rodaste en la superficie, parecía que flotaba sin rodar en absoluto. Esta característica me recordó un poco esa sensación única.

Después de todos los cambios de rendimiento, el juego comenzó a funcionar según lo previsto, incluso en ese dispositivo de bajo rendimiento. No es el más bajo, pero eso estuvo bien para mí. Y luego tengo tiempo para pensar en otras características que impactarán en la sensación general del juego y fueron críticas para mi visión.

El primero fue dejar los rasguños en el piso y se implementó bastante rápido como grupo de calcomanías. Aunque nunca lo veas, definitivamente se suma a la atmósfera de laberinto.

La segunda característica que afectó la sensación general en mis ojos fueron algunas piedras en los pasillos que deberían haber agregado más dinámica al mundo frío y vacío. Eso fue solo lo de la visión, y también sin ningún problema implementado en el juego final. Presentaba una sensación extrañamente satisfactoria cada vez que ves esas pequeñas piedras cayendo en la oscuridad.

Punto de liberación


Una vez que se hayan realizado todas las pruebas y esté satisfecho con el esmalte, ¡estará listo para el lanzamiento!
Para mí, el objetivo principal desde el principio era hacer que la experiencia de un jugador sin distracciones. Así que la decisión fue clara: sin anuncios, sin compras en el juego, sin botines. Para esas características, debes diseñar el juego desde el principio para confiar en que sean una parte esencial de la experiencia. En mi caso, sabía que todo el juego para un jugador promedio será de tres a cuatro horas de experiencia. Así puse un precio fijo razonable y lo dejé pasar. No ha pasado suficiente tiempo desde el lanzamiento para pensar en ventas sustanciales y también sin ninguna promoción todavía. Pero como desarrollador, estoy bastante satisfecho con el juego, y si alguna vez a alguien le gustará, es un éxito para mí.

PS


Al final, quedaron algunas características. Particularmente, todavía hay que hacer algo para completar la atmósfera del juego, pero no es algo que cambie radicalmente la experiencia, por lo que se puede hacer como una actualización posterior al lanzamiento. El resto de las características nunca podrían salir. Lamentablemente para mí, tengo una idea emocionante justo al momento de probar el lanzamiento final. Creo que eso sucedió porque hubo una pausa de una semana en el desarrollo, y tengo un nuevo aspecto después de un regreso. Tal vez algún día habría el segundo juego, pero en este momento todas las ideas esperarán a que vuelva su hora al nuevo ciclo de desarrollo.

PPS
Por favor, si encuentra algunos errores tipográficos o gramaticales, envíe mensajes personales para que yo los corrija.

Source: https://habr.com/ru/post/450468/


All Articles