Isometría, índices z en juegos móviles y su optimización


Hola Habr! Recientemente salimos con nuestro juego , que preparamos durante mucho tiempo y en el proceso del cual se ha acumulado una cantidad considerable de temas interesantes que vale la pena compartir con la comunidad. El tema será de interés no solo para iOS y otros desarrolladores móviles, sino también para todos aquellos que estén interesados ​​en cómo funcionan todo tipo de cosas gráficas, así como para todos los fanáticos de las estrategias 2D, que yo mismo he sido durante la tercera década.

Hoy hablaremos sobre los matices de un tema tan importante como los índices z en una superficie isométrica (sí, no todo es tan simple como parece para algunos sabios). En el mundo 3d, curiosamente, tenemos tres coordenadas, x, y, z, que determinan completamente la posición del objeto en el espacio. La tarea de determinar la proximidad de los objetos a la cámara también está ahí, pero se encuentra completamente en los hombros de OpenGL. El desarrollador solo opera con parámetros de alto nivel, como la profundidad del búfer z, que afectan el rendimiento, pero de lo contrario puede confiar en OpenGL como un cuadro negro: tiene suficiente información.

Se observa una situación completamente diferente en nuestro mundo "pseudo-3D": cada objeto tiene solo (x, y) coordenadas y tamaño del sprite. La primera tarea a la que se enfrenta un programador cuando escribe un motor es la tarea de determinar qué objetos deben superponerse frente a nuestra "cámara" virtual.

Sinopsis


Coordenadas de SpriteKit (donde (0; 0) es el centro del "mundo" e Y sube) en este caso no nos interesa en absoluto, porque no significan nada en nuestro "mundo" isométrico con usted, así que hagamos una reserva: tenemos un campo en forma de diamante como Age of Empires.



Un mosaico con coordenadas (0; 0) se encuentra en la esquina izquierda del rombo, la abscisa X aumenta "abajo" y "derecha", es decir. crece más cerca del observador, la ordenada Y aumenta "arriba" y "a la derecha", es decir disminuye a medida que te acercas al observador.

Además, los rieles deben estar "debajo" del tren, el humo de la chimenea debe estar "encima" del tren. Pero ahora no nos molestaremos con las "capas del ser"; obviamente, nada nos impide hacer tantas "rebanadas" isométricas como desee, trabajando de acuerdo con las mismas reglas. Suponemos que en un mosaico siempre hay un objeto; para mayor claridad, no es necesario más.



Considere los dos trenes de arriba. Obviamente, desde el punto de vista del observador, los vagones deben ubicarse "debajo" del tren, es decir. su índice z debería ser menor. Al mismo tiempo, el tren "superior" debe "superponerse" con el vecino, estar "más lejos". ¿Podemos, teniendo solo las coordenadas (x; y), construir un mapa de índices z para cada mosaico?

Obviamente, sí, usando la siguiente fórmula (pseudocódigo a la rápida):

zIndex = pos.x * field.size.width - pos.y 

Por lo tanto, garantizamos que a medida que crece la ordenada, los objetos se alejan (-pos.y), así como con el aumento de la abscisa, los objetos se acercan (pos.x) y, lo que es más importante, cualquier objeto que tenga una abscisa, digamos 44, estará deliberadamente "más cerca" "Que cualquier objeto que tenga una abscisa 43. Para agregar" capas "aquí (recuerde, los rieles debajo del tren, humo por encima de la tubería), es suficiente agregar una" altura "constante de la capa:

 zIndex = layerZIndex + pos.x * field.size.width - pos.y 

Eso es todo, puedes terminar el artículo y elogiarte por los conceptos básicos de estereometría aprendidos en 10º grado y comenzar la lógica del juego. No? Si solo! ¡Escribiría sobre las cosas obvias! (Bueno, como es obvio, un par de días son aplastados y esto)

Estamos llegando a la parte divertida, avanzando.

Lucha de rendimiento


Todos, al menos una vez, ejecutaron un proyecto de prueba para SpriteKit (o un coco, o cualquier otro motor), vieron números mágicos: fps y nodos.



Obviamente, fps es el número de fotogramas por segundo, los nodos es el número de nodos, principalmente sprites. Pero en la práctica, la mayoría de los fps se configuran no por el número de nodos, sino por otro parámetro, que por defecto no se muestra, pero que también se puede mostrar con una línea: el número de sorteos redibujados.



En la misma escena, como puede ver ahora, el número de nodos es de aproximadamente 6000 y el número de representaciones es de aproximadamente 120. Esto es con el zoom mínimo (la cámara está lo más cerca posible de la superficie), 1: 1.

Ahora muevamos la cámara a la distancia máxima (en nuestro juego es 2.5: 1)



Cambiamos la escala solo 2,5 veces (en el ejemplo, lejos de que se dibujen todos los objetos), ¡y el número de sorteos aumentó de 5 a 6 veces con el recuento de nodos sin cambios!

Por supuesto, el número de representaciones afecta a fps inconmensurablemente más que el número abstracto de nodos. SpriteKit simplemente no dibuja nodos que no caen en la ventana gráfica (en la cámara). La única excepción que he encontrado hasta ahora son los emisores de partículas, que siempre se dibujan, independientemente de si son visibles o no.

Ahora hablemos sobre lo que significa este dibujo de "dibujo". La tarjeta de video tiene todos los nodos "capas", guiados por sus índices z. Y recorre toda la imagen una y otra vez, desde la más baja hasta la más alta. El número de tales ciclos de representación es sorteos.

Ahora comprende que si dibuja cada pequeño objeto (y tenemos un mapa grande, aproximadamente 6000 x 3000) con su propio índice z, esto arruinará el rendimiento de cualquier teléfono.

Los problemas se ven mejor en los viejos 5 y 5, pero la presencia del iPhone 10 no garantiza nada: con el enfoque incorrecto, puede deshacerse de cualquier hardware potente. En nuestro juego, uno de los pilares fue la claridad extrema. En el zoom más cercano, los sprites uno a uno corresponden a píxeles retin. Debo decir que en la mayoría de los juegos móviles la resolución es mucho menor, por lo que los requisitos no son tan enormes, pero lo hicimos cualitativamente, como para nosotros mismos ...

Entonces tienes que ir a los trucos.

  • Todos los objetos con los que el jugador no interactúa, y que están en el mismo nivel en la coordenada X, generalmente se pueden combinar en un sprite. Para una tarjeta de video, es mucho más fácil dibujar un sprite grande que 10 pequeños. Por lo tanto, los carriles forestales entre caminos son sprites integrales que consisten en varios árboles. Y los árboles que no se superponen a los caminos y otros árboles generalmente están cosidos en el mapa. En alfa, por cierto, hubo bastantes errores cuando un roble centenario creció justo debajo de los rieles de un tren o debajo de un semáforo ferroviario, así que prueba cuidadosamente tu juego para no entretener a los usuarios.
  • Los objetos que tienen un índice z se dibujan en el orden en que aparecen en la tarjeta de video. Es decir al agregar objetos "distantes" antes que los "cercanos", caerán correctamente, pero no aumentarán el número de representaciones de tarjetas gráficas.

Todo esto le permite reducir el número de sorteos a veces, arreglando fps incluso en un iPhone antiguo. Tuve que limitar severamente algunos efectos a ellos, pero Apple no ha publicado actualizaciones para ellos por un año, ¡un pecado se quejará!

Elevacion


Bueno, todo, el motor está listo, ¿puedes comenzar algo interesante ya? Alguien puede, pero es demasiado temprano para nosotros. Después de todo, el tren debería abandonar el túnel de manera hermosa, y aquí no todo es tan simple como parece.



El tren debe estar ubicado "más alto" que la pared "lejana" del túnel, y "más bajo" que el techo del túnel y las montañas que lo siguen. Es hermoso, después de todo, cuando el mapa es tan multinivel, con cambios de elevación, una vez más, no estamos haciendo tonterías sin alma, ¡sino lo que nos gusta a nosotros mismos!

Pero volviendo a los detalles, para esto el mapa se "cortó" de la siguiente manera.



La pared interna del túnel y todo lo demás a la izquierda es más baja y



La parte superior del túnel junto con las montañas en las que fluye. Aquí, ninguna generación procesal de índices z ayudará, solo un código duro bielorruso severo.

El atento habrayuzer notó en la captura de pantalla del juego que cerca de los túneles los árboles estaban cuidadosamente "cortados", exponiendo la arena virgen de la playa. Este defecto aparentemente proviene de la imposibilidad fundamental de realizar tales plantaciones de árboles en 2D. El tren, al salir del túnel, debe estar deliberadamente "encima" de los árboles que se superponen, cubriéndolos a sí mismos. ¡Pero estos mismos árboles deberían superponerse al techo del túnel, debajo del cual el tren debería llamar! Y el techo debería ser más alto que el tren, por lo que en un círculo, tenemos una contradicción lógica ...

Por una razón similar, debido a la imperfección del motor gráfico, en juegos antiguos como Duke Nukem y Doom2 no hay grandes diferencias en las alturas y pisos de los edificios.

Es por eso que los árboles no crecen cerca de los túneles.

Espero que haya sido interesante, el juguete en vivo aquí (gratis) , el próximo artículo de la serie tratará sobre el hermoso agua realista en 2D, ¡no te lo pierdas!

PD: Por cierto, un video para llamar la atención se puede ver en YouTube en calidad normal.

PPS El juego hasta ahora solo está disponible en la CEI, Canadá e Irlanda, si alguien quiere mirar desde otros países, envíe un correo electrónico personal con appleId; lo agregaré a TestFlight

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


All Articles