Gestiona una gran cantidad de actores independientes en tiempo real

8

Estoy trabajando en un juego de estrategia en tiempo real a gran escala, idealmente con miles de unidades activas a la vez, pero tengo problemas para administrar todas las unidades a la vez sin que se vuelva sorprendentemente lento. El problema es que lleva un tiempo actualizar las posiciones y los estados de todo cada paso del tiempo. ¿Conoces patrones / metodologías / consejos de diseño para mitigar esto?

Slubb
fuente
1
aunque su pregunta puede parecer muy diferente, puede usar el mismo algoritmo que se explica aquí . no es necesario usar el procesamiento paralelo en ese algoritmo, con solo uno obtendrá un impulso de alto rendimiento.
Ali1S232
Poner en paralelo la actualización no ayudará si, por ejemplo, tienes dos núcleos y actualizar la mitad de ellos ya lleva demasiado tiempo, pero si tienes varios núcleos disponibles y no los estás utilizando, debería ayudar. Idealmente, querrá una solución que no requiera que actualice cada unidad individual cada paso de tiempo, o una forma de simplificar la actualización para que pueda. ¿Qué tan grande es este paso de tiempo? Es independiente de los cuadros de dibujo, ¿verdad?
Blecki
44
Lo primero que puede hacer es reconocer que su velocidad no tiene nada que ver con la cantidad de actores independientes. Tiene que ver con lo que están haciendo esos actores . Puedo tener cientos de miles de actores independientes actualizados> 60 fps si todo lo que están haciendo es if not dead position += 1o una actualización de actor <1 fps si va en un bucle infinito. Algunos de sus algoritmos, algunas partes de lo que están haciendo estas unidades, son demasiado costosos como los hace y eso es todo. Probablemente hay muchas causas posibles diferentes, y muchas estrategias posibles diferentes para cada una.
doppelgreener

Respuestas:

4

Hay dos cosas distintas a tener en cuenta al medir y optimizar el rendimiento de un sistema de entidades a gran escala.

En el nivel bajo, tiene la representación física de sus entidades que tiende a reducirse al uso de diseños de almacenamiento eficientes como SoA (estructuras de matrices) para reducir el costo de iterar y actualizar todas las entidades activas.

En el nivel superior, tienes lógica de toma de decisiones, lógica general del juego, IA y búsqueda de caminos. Estas son todas las tareas que tienen en común que no tienen que ejecutarse a la misma velocidad de actualización que su representación.

Como obtendría un tiempo de trama desigual si toma el enfoque ingenuo de solo hacer esas tareas cada N tramas, tiende a ser beneficioso amortizar el costo en varias tramas.

Si la tarea es de naturaleza incremental, puede ejecutar parte del algoritmo en cada cuadro y utilizar resultados parciales en sus actualizaciones.

Si la tarea es en gran parte monolítica pero separable por entidad, puede realizar esa tarea para un subconjunto de sus entidades de juego por fotograma, rotando entre ellas de forma circular. Esto tiene el beneficio de reducir la complejidad de cosas como la búsqueda de caminos y la IA, ya que no todos tienen que tratar de actuar a la vez.

En el RTS táctico a gran escala en el que trabajé, nos centramos en tener estructuras de datos robustas para consultar la representación de bajo nivel en los algoritmos de alto nivel, para encontrar a los vecinos de las entidades del juego. El proceso de actualización de bajo nivel actuó según las intenciones proporcionadas por la simulación de alto nivel de actualización lenta, y al final se redujo a una simulación de partículas barata, aumentando a miles.

Lars Viklund
fuente
+1. Mis pensamientos exactamente, particularmente reduciendo la lógica a grupos administrados que solo se procesan cada pocos ciclos, con todos esos grupos potencialmente escalonados para un procesamiento uniforme.
Ingeniero
1

Por lo que puedo recordar, siempre tendrás menos de 10,000 unidades por juego. No hay ningún juego que pueda recordar con más que ese número, aunque la Tierra del Imperio podría llegar hasta 14000 a través de un truco, pero nadie llegará a ese punto. así que solo tener una matriz estática de 10,000 objetos parece ser más de lo necesario.

como sabe, iterar más de 10000 objetos no es gran cosa, pero puede consumir mucho tiempo si su algoritmo funciona más lento que O (n). por ejemplo, si intenta verificar la detección de colisión de cada dos objetos, llevará tiempo O (n ^ 2), lo que significa mucho tiempo. así que tienes que romper tus algoritmos de alguna manera. revisemos un algoritmo de muestra para cada cosa que se me ocurra en este momento:

  1. detección de colisión: para cada algoritmo de detección de colisión, debe verificar cada dos objetos, pero puede eliminar algunas comprobaciones al iniciar los bucles. Como sugerí en los comentarios, puede usar el mismo algoritmo dado para esta pregunta . no es necesario usar múltiples hilos ni nada, incluso con un hilo y 4 regiones, reducirá sus comprobaciones de n * (n-1) a 4 * (n / 4) ((n-1) / 4), y al optimizar el número de regiones puede obtener resultados aún mejores. Creo que al usar las mejores regiones numéricas, incluso puede llegar a O (n log (n)).

  2. tienes que generar una ruta para cada objeto en movimiento. El sistema habitual que he visto hasta ahora es algo muy simple: cada vez que el jugador ordena a las unidades que se muevan a algún lugar, la computadora calcula su camino, después de eso, en cada ciclo, si el objeto puede moverse, se mueve si no puede saltarse ese ciclo. No hay nada especial. aunque también puede cambiar los algoritmos que se proporcionan aquí para reducir las llamadas de búsqueda de rutas y encontrar rutas en tiempo real para cada grupo de unidades, pero eso realmente no es necesario.

  3. tienes que verificar si alguna bala o bomba o algo similar golpea una de las unidades: puedes usar las mismas regiones que creaste para la detección de colisiones aquí.

  4. para seleccionar unidades también puede usar las mismas regiones.

en general, sugeriría usar una matriz estática (o una matriz dinámica con tamaño reservado) de 10,000 o 20,000 como máximo. luego use algo alrededor de 10 o 15 bucles cada uno iterando sobre todas las unidades. esa es una gran variedad real que contiene todas las unidades de todos los jugadores. así que cada índice tiene datos sobre el propietario de la unidad y el tipo de unidad. También puedes crear otros arreglos para cada jugador. en cada índice de esta matriz secundaria solo tendrá que almacenar punteros a los objetos en la matriz principal.

si tiene alguna otra pregunta, agregue comentarios para agregarlos a mi respuesta.

Ali1S232
fuente
Recuerdo haber tenido más de 40,000 en Empires Dawn of the Modern World :). Es una pena que el renderizador solo pudiera mantener alrededor de 1000 en la pantalla antes de que comenzaran a desaparecer, pero el resto del juego funcionó bien :).
Caviar desacelerado
@daniel: eso no es gran cosa, los generales no tenían ninguna limitación en el recuento de unidades. Solo estaba dando una medida de un buen número de unidades para basar mis cálculos matemáticos. 40000 y 10000 no son muy diferentes entre sí.
Ali1S232