¿Cómo implementar el viaje en el tiempo en un juego?

10

Me preguntaba cómo implementar el viaje en el tiempo en un juego. Nada súper complejo, solo inversión de tiempo como lo que hay en Braid, donde el usuario puede retroceder / adelantar el tiempo en 30 segundos o lo que sea.

Busqué mucho en la web, pero mis resultados generalmente se referían al uso del tiempo como "son las 3:00" o un temporizador y tal.

Lo único que se me ocurrió fue usar 2 matrices, una para la posición x del jugador y la otra para la posición y del jugador, y luego iterar a través de esas matrices y colocar al personaje en esa posición a medida que retroceden / avanzan rápidamente. ¿Eso podría funcionar? Si funcionara, ¿qué tan grande debería ser la matriz y con qué frecuencia debo almacenar las x e y del jugador? Si no funciona, ¿qué más puedo probar?

¡Gracias por adelantado!

Alex
fuente
11
¿No lees las noticias ( ust.hk/eng/news/press_20110719-893.html )? Acaban de demostrar que el viaje en el tiempo no es posible. Por lo tanto, es imposible codificar.
Debe pensar una posible semántica para el viaje en el tiempo, solo después puede comenzar a pensar en la implementación.
Paŭlo Ebermann
2
Aprende algunas matemáticas vectoriales . Si está proponiendo dos matrices separadas que sugieren que nunca ha trabajado con ellas. Considero que es vital para un programador de juegos saber cuánto pueden simplificar las cosas.
doppelgreener
55
import universal.back2future.FluxCapacitor;
jhocking

Respuestas:

6

La idea de matriz es más o menos cómo se implementó en Braid. Cuando las únicas cosas que actúan sobre un personaje son la gravedad, la entrada del teclado / joypad y otros caracteres, solo necesitas almacenar la posición y la velocidad en cada paso para saber todo lo importante sobre ese personaje. Si almacena 10 instantáneas por segundo por personaje, entonces todavía es menos de 50K por un minuto del historial de un personaje, fácilmente manejable en la mayoría de los sistemas, y también puede encontrar formas que son más eficientes.

Kylotan
fuente
Este es el camino correcto. Por ejemplo, almacenar comandos activos: pulsaciones de teclas con marcas de tiempo. Puede extrapolar la mayoría de los otros comportamientos si el sistema es determinista. El rastreador de 10 fps está bien para un sistema de rebobinado, incluso menos podría ser aceptable, siempre que se conserven los comandos reales, en efecto, el estado o los cambios de estado de los objetos.
karmington
4

Lea sobre el patrón de comando . Proporciona acciones para deshacer (y para volver a hacerlas más tarde). Eso manejaría más que solo la posición de un barco, sino todas las acciones que el jugador realiza.

Pero creo que su idea de matriz también es sólida.


fuente
Probablemente no sea una gran idea: además de ser más intensivo en memoria (cada vez que agrega la velocidad de una entidad a su posición, necesita almacenar eso como una "acción") , requiere prácticamente matemática de punto fijo, ya que si usa flotante -punto para sus posiciones / velocidad, (x+v)-vpuede no ser igual a x.
BlueRaja - Danny Pflughoeft
1
@BlueRaja: no veo dónde ese enfoque requeriría mucha memoria. A 100 FPS y almacenando los últimos 10 segundos, debe almacenar 1000 n-tupels de comandos, donde n es como máximo 5 más o menos. O, mejor aún, almacena solo la posición absoluta en cada uno de esos cuadros, y para el rebobinado, simplemente anima al personaje hacia atrás a lo largo de ese camino. Eso también eliminaría cualquier posible problema de coma flotante y lo lleva de vuelta exactamente a donde comenzó.
Hackworth
3

En lugar de tener dos matrices separadas, probablemente debería tener una clase que describa la posición del jugador (probablemente ya haya una clase Point en Java ... últimamente soy un tipo C #) y use una matriz única para mantener las posiciones pasadas.

Debe configurar un "anillo de búfer", lo que significa que cuando llegue al final de la matriz, vuelva al principio de la matriz, sobrescribiendo las entradas más antiguas. Si viaja en el tiempo, lo contrario es cierto (cuando llegue al principio, circule hasta el final).

Si desea mantener 30 segundos de datos pasados, debe conocer su velocidad de fotogramas si desea preasignar espacio y usar una matriz de tamaño fijo. Si renderizas el juego a 10 cuadros / segundo, multiplicado por 30 segundos, son 300 elementos.

Eric J.
fuente
2

GDCVault tiene una conferencia de Jon Blow (el creador de Braid ) en su sitio llamada The Implementation of Rewind in Braid por $ 3.95. Apuesto a que tiene la información que deseas;)

EDITAR: Probablemente no estará en Java, pero las ideas deberían ser válidas.

NoobsArePeople2
fuente
¿Sabes si también venden la transcripción o solo el audio?
o0 '.
No pude encontrar nada a través de una búsqueda rápida del sitio. ¿Quizás podrías usar algún software de transcripción ?
NoobsArePeople2
1

Como dijo Erik J , almacenar las posiciones pasadas del jugador como una colección de objetos puntuales en un buffer de anillo suena razonable.

Sin embargo, sugeriría usar una cola para implementar el búfer. Es mucho más barato actualizar que una matriz y no tiene que conocer su velocidad de fotogramas por adelantado:

update():
   time_queue.push(player.positions)
   if current_time() - start_time > n:
       queue.pop()

Esto todavía no considera las velocidades de cuadro variables o lo que debería suceder si realmente viaja en el tiempo, por lo que le sugiero que guarde una marca de tiempo con cada entrada y verifique eso en su lugar:

update():
    time_queue.push({
        'pos': player.positions,
        'time': current_time()
    })
    first_entry = queue.peek()
    while current_time() - first_entry['time'] > n:
       queue.pop()
       first_entry = queue.peek()

¡Espero que esto ayude!

HumanCatfood
fuente
1

Hay un patrón de diseño llamado Memento , creo que es un punto de partida para un juego como Braid

El patrón de recuerdo es un patrón de diseño de software que proporciona la capacidad de restaurar> un objeto a su estado anterior (deshacer mediante reversión).

El patrón de recuerdo es utilizado por dos objetos: el originador y un cuidador. El originador es un objeto que tiene un estado interno. El cuidador le hará algo al creador, pero quiere poder deshacer el cambio. El cuidador primero le pide al originador un objeto de recuerdo. Luego hace cualquier operación (o secuencia de operaciones) que iba a hacer. Para volver al estado anterior a las operaciones, devuelve el objeto de recuerdo al originador. El objeto de recuerdo en sí es un objeto opaco (uno que el cuidador no puede o no debe cambiar). Al usar este patrón, se debe tener cuidado si el autor puede cambiar otros objetos o recursos: el patrón de recuerdo opera en un solo objeto.

http://en.wikipedia.org/wiki/Memento_pattern

Información adicional aquí: http://dofactory.com/Patterns/PatternMemento.aspx

Marcelo Assis
fuente
2
No veo cómo esto debería ayudar. Parece que es un "retroceso instantáneo", mientras que el OP pidió algo suave como el de Braid. Tal vez leí mal algo?
o0 '.
Este patrón no implica en una única reversión, puede crear una "línea de tiempo" de acciones, por ejemplo. Aquí hay una publicación de blog de Brazillian sobre el uso de este patrón: abrindoojogo.com.br/padroes-de-projeto-memento Aquí hay un ejemplo hecho en Flash: abrindoojogo.com.br/files/fasteroids.swf Move: Arrows | Dispara: espacio | Acciones de rebobinado: Retroceso
Marcelo Assis
1

Se lanzó un juego para XBox360 que involucraba la manipulación del tiempo. Era mediocre, así que no puedo recordar el título en este momento. De todos modos, en una entrevista con un desarrollador, describieron cómo manejaron la manipulación del tiempo:

Cada X cuadros (con valores más bajos de X que conducen a una manipulación más precisa), tomas una "instantánea" del mundo del juego en ese punto y lo asocias con un tiempo en el juego.

Mientras se juega a través del juego normalmente, en el tiempo, cada entrada y reacción contribuye al conjunto de instantáneas en algún momento en el futuro.

El mundo del juego luego itera entre la instantánea en el momento actual y la instantánea X fotogramas en el futuro.

Luego, cuando desee invertir el tiempo, simplemente configure la dirección del tiempo para que esté al revés, de modo que esté iterando entre los cuadros X del presente y de la instantánea en el pasado (mientras deshabilita la capacidad de crear instantáneas futuras).

Jordaan Mylonas
fuente
+1 para el punto sobre la granularidad de las instantáneas.
Omar Kooheji
0

Simplemente puede tratar el tiempo virtual del juego como otra dimensión similar al espacio. Entonces, ¿qué pasa en el tiempo desde el exterior es un simple movimiento n + 1 dimensional en el universo virtual del juego.

Suponiendo cierta interacción del usuario y algún tipo de sistema de física que determina el comportamiento de su universo cuando no hay entrada del usuario, todo lo que necesita registrar es el efecto de las interacciones del usuario (por ejemplo, cambios en los vectores de velocidad / aceleración de la dimensión n + 1) , ya que tu física debería ser reversible en el tiempo.

De esta forma, necesitarías mucha menos memoria para calcular el estado del universo del juego en cualquier coordenada de tiempo.

biziclop
fuente
Como mencioné en otro comentario, la física en los videojuegos generalmente no es reversible en el tiempo, porque cuando se usan números de punto flotante, (x+v)-vpodría no ser igual ax
BlueRaja - Danny Pflughoeft
0

Digamos que una entidad tiene una velocidad, rotación, posición x e y. Estos son, con aceleración, los estados básicos de movimiento, valores, como se llame. Puede guardar los datos de dos maneras:
1. Guardar rotación, posición x e y
2. Guardar rotación, velocidad xy velocidad y

Si tiene una velocidad fija, también podría guardar solo la rotación, o guardar solo una velocidad para ambos ejes.

Es necesario guardar la rotación en los juegos, a menos que su entidad tenga una rotación estática, lo que no es en la mayoría de los casos.

Dicho esto, es necesario usar una lista de objetos para múltiples valores. Si tiene un buen sistema de temporizador, que, por ejemplo, llama a los métodos de actualización 20 veces en un segundo y, por lo tanto, es independiente de fps, puede crear una matriz de 20 * 30 objetos para almacenar los valores de movimiento que necesita durante los últimos 30 segundos . No se recomienda el uso de una matriz simple, ya que tendría que mover cada elemento de un índice a la izquierda de cada llamada de actualización.

Basado en esto, puede revisar la lista o lo que sea para regresar. Si realmente desea obtener un efecto "realista", use esta técnica para todos los objetos en movimiento. Pero esto está relacionado con el diseño del juego.

Si destruye objetos, recuerde agruparlos para asegurarse de no estresar a su amigo ordenado, el Sr. Garbage;)

Marco
fuente