design patterns - reusable - Conceptualmente, ¿cómo funciona la repetición en un juego?
factory pattern (12)
Tenía curiosidad de cómo se podría implementar la repetición en un juego.
Inicialmente, pensé que habría solo una lista de comandos de cada acción de jugador / ai que se tomó en el juego, y luego ''vuelve a jugar'' el juego y deja que el motor rinda como de costumbre. Sin embargo, he visto repeticiones en juegos de FPS / RTS, y tras una inspección cuidadosa, incluso cosas como las partículas y fallas gráficas / audibles son consistentes (y esas fallas técnicas generalmente son consistentes).
Entonces, ¿cómo sucede esto? En los juegos de ángulo fijo de cámara, pensé que podría simplemente escribir cada fotograma de la escena completa en una secuencia que se almacena y luego reproducir la transmisión nuevamente, pero eso no parece ser suficiente para los juegos que te permiten pausar y mover la cámara alrededor. Tendría que almacenar las ubicaciones de todo en la escena en todos los puntos en el tiempo (¿No?). Entonces, para cosas como las partículas, hay muchos datos que impulsar, lo que parece ser un gran atractivo para el rendimiento del juego mientras se juega.
Creo que tu pensamiento inicial fue correcto. Para crear una repetición, almacena todas las entradas recibidas del usuario (junto con el número de fotograma en el que se recibió) junto con las semillas iniciales de cualquier generador de números aleatorios. Para reproducir el juego, reinicia tus PRNG usando las semillas guardadas y alimenta el motor del juego con la misma secuencia de entrada (sincronizada con los números de los cuadros). Dado que muchos juegos actualizarán el estado del juego en función de la cantidad de tiempo que pasa entre cuadros, es posible que también deba almacenar la longitud de cada cuadro.
Dado el estado inicial y una serie de acciones con marcas de tiempo , simplemente revise la secuencia ya que se supone que las acciones registradas tienen una repetición.
Para lograr que los eventos aleatorios vuelvan a ocurrir exactamente igual, use números seudoaleatorios y guarde la semilla en el archivo de reproducción.
Siempre que use el mismo algoritmo para generar los números aleatorios de la semilla, puede recrear todos los eventos tal como ocurrieron en el juego en vivo sin necesidad de instantáneas completas del estado del juego.
Esto requerirá que las repeticiones sean vistas secuencialmente , pero eso es bastante normal para las repeticiones de juegos (ver Starcraft 2). Si desea permitir el acceso aleatorio a la línea de tiempo, puede tomar instantáneas de estado completo a intervalos establecidos (por ejemplo, cada minuto), para saltar por la línea de tiempo en una granularidad establecida.
Dan Bryant
Además, el registro de semillas aleatorias no sería suficiente para el soporte de rebobinado, ya que la progresión aleatoria no es un procedimiento reversible sin un soporte especial en toda la lógica que depende de la aleatoriedad. Es más flexible registrar los resultados de las operaciones aleatorias como parte de la secuencia de eventos.
Eso es exactamente lo que pensé al principio cuando intentaba descubrir cómo lo hacían para que el juego siempre repitiera lo mismo. Con Doom pensé en lo aleatorio que eran los brotes: D. Guarde cualquier número aleatorio que haya usado, descubrí que podría ser una solución. Eso fue antes de encontrar un documento en pdf sobre la tecnología Crysis. Algunas texturas sonoras y la disposición de la hierba o el árbol parecían estar usando la pseudoaleatorización con semillas fijas reversibles para que no viera una alteración en la disposición del ruido, los árboles y la hierba cada vez que mira.
Evitando al mismo tiempo, almacenar millones de árboles y posición de los pozos de hierba. Aparentemente, la secuencia pseudoaleatoria puede reproducir el mismo en cualquier momento, ya que la lógica es fija, solo para hacer una secuencia de números falsa estadísticamente aleatoria.
El problema de tener una repetición constante es el mismo (bueno, más fácil) como tener un juego multijugador consistente.
Como otros mencionaron antes, las repeticiones en los juegos RTS se almacenan registrando todas las entradas (que tienen un efecto. El desplazamiento no tiene ningún efecto). El modo multijugador transmite todas las entradas, también
Grabar toda la entrada no es solo una conjetura, hay una biblioteca para leer las repeticiones de Warcraft3 que revela esto.
la entrada incluye marcas de tiempo para esta respuesta.
Hay dos métodos principales:
- Almacenamiento de eventos (como acciones de jugador / ai), tal como dices.
- Estado de almacenamiento (estado de juego completo, ubicaciones de objetos en fe, en momentos consecutivos).
Depende de lo que quieras hacer. A veces, el almacenamiento de eventos es mejor, ya que generalmente requiere menos memoria. Por otro lado, si desea proporcionar repeticiones que se puedan reproducir a diferentes velocidades y desde diferentes puntos de inicio, es mejor almacenar estados. Al almacenar estados, también puede decidir si almacenarlos después de cada evento o solo 12 o 25 veces por segundo; esto podría reducir el tamaño de la reproducción y facilitar el rebobinado / avance rápido.
Tenga en cuenta que "estado" no significa estado gráfico. Más algo como posiciones de unidades, estado de los recursos, etc. Cosas como gráficos, sistemas de partículas, etc., suelen ser deterministas y pueden almacenarse como "animación X, tiempo Y: Z".
Algunas veces las repeticiones se usan como esquema anticheating. Entonces, almacenar eventos es probablemente el mejor aquí.
Lanza mis dos peniques adentro.
Depende de lo que quieras, la reproducción se puede realizar a través de
- Grabación de búfer de video y reproducción posterior,
- Capturar el estado del objeto en cada cuadro y reproducirlo más tarde,
La mayoría de las veces, la gente quiere una repetición interactiva, así que 2. es el camino a seguir. Luego, dependiendo de sus limitaciones, hay varias formas de optimizar este proceso
- garantizar que el sistema sea una simulación determinista *, de modo que cada entrada genere un resultado consistente y esperado
- si se requiere aleatoriedad, asegúrese de que los números aleatorios se reproduzcan exactamente en un momento posterior [vea el sembrado con Pseudo Generadores de Números Aleatorios PRNG, o use conjuntos aleatorios enlatados]
- divida los elementos del juego en elementos "mecánicos" y "estéticos". los elementos mecánicos afectan el resultado [p. ej., columna que cae y bloquea el camino], los elementos estéticos son para mostrar y no influyen en ningún proceso de toma de decisiones en el sistema [por ejemplo, efectos de partículas visuales como chispas].
Realmente es un tema fascinante. Recuerdo que un título de lanzamiento para Xbox Wreckless original tenía una buena función de reproducción. Desafortunadamente, en más de una ocasión la repetición se estropeó;)
oh sí, ¿cómo podría olvidar alguien a Blinx Time Sweeper ? ¡excelente repetición interactiva que se incorporó a la mecánica del juego!
* = Parece que hay algunos comentarios con respecto al paso del tiempo. Estoy usando "simulación" aquí para capturar esta característica. en esencia, su motor necesita poder producir marcos de tiempo discretos. incluso si un marco de reproducción tarda más o menos en procesarse que el original, el sistema debe percibir que el mismo delta de tiempo ha pasado. esto significa registrar el paso de tiempo del fotograma con cada entrada grabada y suministrar este delta al reloj del motor.
NVidia PhysX (un motor de simulación física que se usa a menudo en juegos) es capaz de registrar el estado completo de la escena física a lo largo del tiempo. Esto incorpora todas las entradas de conducción del motor del juego, lo que significa que no necesita rastrear semillas de números aleatorios como otros han sugerido. Si toma este volcado de escena, puede reproducirlo en una herramienta externa (provista por NVidia), que es muy útil para rastrear problemas con sus modelos físicos. Sin embargo, también podría usar el mismo flujo de física para controlar su motor gráfico, lo que le permitiría tener un control normal de la cámara, ya que solo se ha grabado la física que maneja los gráficos. En muchos juegos, esto incluye los efectos de partículas (PhysX incluye algunos sistemas de partículas muy sofisticados.) En cuanto al sonido, supongo que se graba al pie de la letra (como una transmisión de sonido), pero no estoy seguro.
Starcraft y Starcraft: Brood War tenía una función de reproducción. Después de completar una partida, puede optar por guardar la reproducción para verla más tarde. Mientras reproduce, puede desplazarse por el mapa y hacer clic en unidades y edificios, pero no cambiar sus comportamientos.
Recuerdo que una vez vi una repetición de un partido que se había jugado en el juego original, pero la repetición se estaba viendo en Brood War. Para los que no están familiarizados, Brood War contiene todas las unidades y edificios originales, así como una variedad de otros nuevos. En el juego original, el jugador había derrotado a la computadora creando unidades que la computadora no podía contrarrestar fácilmente. Cuando jugué la repetición en Brood War, la computadora tuvo acceso a diferentes unidades, que creó y usó para derrotar al jugador. Así que el mismo archivo de reproducción resultó en un ganador diferente dependiendo de qué versión de Starcraft estaba reproduciendo el archivo.
Siempre encontré el concepto fascinante. Parecería que la función de repetición funcionó registrando todas las entradas del jugador, y asumió que la computadora respondería a esos estímulos de la misma manera cada vez. Cuando las entradas del jugador se alimentaron en el reproductor de Starcraft original, el juego se jugó exactamente como lo hizo en la partida original. Cuando se introdujo la misma entrada exacta en el repetidor de Brood War, la computadora reaccionó de manera diferente, creó unidades más fuertes y ganó el juego.
Algo a tener en cuenta si está escribiendo un motor de repetición.
Su idea original es correcta, y para los efectos realmente complejos, no se recuerdan exclusivamente. Por ejemplo, el sistema de repetición de Warcraft 3 no almacena el estado de las animaciones o los efectos de partículas en el caso de efectos aleatorios, etc. Además, la mayoría de las cosas se pueden calcular computacionalmente desde un punto de partida de una manera determinística, por lo que para la mayoría de los sistemas que usan variables aleatorias (una explosión de partículas que da una compensación aleatoria, por ejemplo), todo lo que necesitaría es el tiempo del efecto y la semilla aleatoria. Podrías volver a generar el efecto sin saber realmente cómo terminará luciendo ... sabiendo que está pasando por una ruta de código determinista.
Si pensamos en ello puramente conceptualmente, para reproducir una línea de tiempo de eventos, todo lo que necesita son las acciones del usuario. El programa reaccionará exactamente de la misma manera, excepto en el caso de variables aleatorias. En este escenario, puede ignorar la aleatoriedad (¿REALMENTE importa si los efectos se ven EXACTAMENTE iguales, o pueden ser re-generados aleatoriamente), o almacenar el valor inicial y simular la aleatoriedad?
Técnicamente deberías escribir tu motor para que sea determinista, eso no es aleatoriedad. Suponiendo que un personaje del juego apunte al brazo de un oponente y dispare un arma, se debe aplicar la misma cantidad de daño al oponente en todos los casos.
Suponiendo que una bomba detona en la ubicación X, las partículas producidas por esa explosión siempre deberían dar como resultado el mismo resultado visual. Si necesita aleatoriedad, cree un conjunto de números aleatorios, seleccione un valor inicial cuando se juegue el juego y guarde ese valor inicial en la repetición.
En general, tener aleatoriedad en un juego es una mala idea. Incluso para cosas como multijugador, no puedes tener la mitad de tus jugadores capaces de ver alrededor de una explosión, mientras que los demás no pueden simplemente porque no obtuvieron el valor aleatorio correcto.
Haz que todo sea determinista, y deberías estar bien.
Tal vez podrías simplemente guardar una pila de comandos enviados por cada jugador. Entonces, en lugar de evitar que una bomba explote en un momento y momento determinado, o que se destruya un determinado automóvil, simplemente guarde las teclas presionadas por cada jugador. Luego, en la repetición, simplemente simula el juego como hubiera sucedido con esas pulsaciones. Siento que tiene el potencial de ocupar menos espacio, pero nunca he trabajado en un sistema de reproducción como ese.
Interesante pregunta, sin embargo. Me interesaría cómo se hace en los juegos profesionales.
Yo creo que en ciertos incrementos el juego tomaría una instantánea del estado de todo (TODO). Luego, cuando se repite la repetición, se puede usar simplemente la interpolación lineal para completar los "agujeros". Al menos así es como creo que se haría.
Tiene razón en que registrar las entradas no sería confiable / no garantizaría el mismo resultado. El juego definitivamente tiene que hacer un seguimiento del estado de todos los objetos (o al menos los más importantes)