¿Cómo codificar Time Stop o Bullet Time en un juego?

11

Estoy desarrollando un juego de plataformas RPG para un jugador en XNA 4.0. Me gustaría agregar una habilidad que haga que el tiempo se "detenga" o disminuya, y que solo el personaje del jugador se mueva a la velocidad original (similar al hechizo Time Stop de la serie Baldur's Gate). No estoy buscando una implementación exacta, sino algunas ideas generales y patrones de diseño.

EDITAR: Gracias a todos por el gran aporte. Se me ocurrió la siguiente solución

    public void Update(GameTime gameTime)
        {

            GameTime newGameTime = new GameTime(gameTime.TotalGameTime,
 new TimeSpan(gameTime.ElapsedGameTime.Ticks / DESIRED_TIME_MODIFIER));
            gameTime = newGameTime;

o algo por el estilo. De esta manera, puedo establecer un tiempo diferente para el componente del reproductor y diferente para el resto. Ciertamente, no es lo suficientemente universal como para trabajar en un juego donde el tiempo de deformación como este sería un elemento central, pero espero que funcione para este caso. No me gusta el hecho de que ensucia el ciclo principal de actualización, pero sin duda es la forma más fácil de implementarlo. Supongo que es esencialmente lo mismo que sugirió tesselode, así que le voy a dar la marca verde :)

David Miler
fuente

Respuestas:

8

Esta podría ser una mala solución, pero no necesariamente. Si está usando el tiempo delta, puede cambiar eso para cambiar la velocidad de ciertas cosas.

Por ejemplo:

player.update(dt)
dt = dt * .5 --half speed
enemy.update(dt)

Esto, por supuesto, solo funciona si puedes saber cuándo estás actualizando al enemigo en lugar de otra cosa. También podría simplemente darle a todo un valor de velocidad y hacer algo como:

x = x + xspeed * dt * speed
tesselode
fuente
La primera parte tiene mucho sentido, la segunda parte no está clara
AturSams
2
Simplemente dele a cada objeto que mueva una variable de velocidad que pueda cambiar, y cuando tenga una transformación (de x, por ejemplo), multiplique la magnitud por la variable de velocidad.
tesselode
Tiene sentido ahora. :)
AturSams
La segunda idea suena ... apagada. Simplemente escalar el movimiento por el factor de "velocidad" puede funcionar para objetos impulsados ​​por la física, pero la IA podría reaccionar a la velocidad normal, con solo su movimiento ralentizado / deteriorado.
¿Qué quieres decir con que la IA podría reaccionar a la velocidad normal? ¿Qué código tendría la IA que no podría tener una variable de velocidad aplicada?
tesselode
3

Usar el tiempo delta (milisegundos que pasaron desde el último fotograma) puede no ser suficiente para ralentizar a los enemigos. Cosas como la tasa de ataque podrían implementarse en función del último tiempo de ataque. Si bien ralentizará el movimiento si se basa en el tiempo, descuidará la velocidad de ataque, el lanzamiento de hechizos y otros efectos (regeneración de salud, duración de los efectos de hechizo) ... y tal

Si quieres ralentizar un gran grupo de elementos del juego en un juego para un solo jugador, puedes crear un segundo reloj interno para cada criatura, el reloj comienza en el momento actual cuando aparece la criatura. Cuando se lanza un hechizo lento, cada cuadro, el reloj se incrementa en un x% del tiempo que realmente pasó. Todo el comportamiento del monstruo está determinado por su reloj interno. Si varios monstruos tienen resistencia a la lentitud, pueden usar su propio reloj, es básicamente un número entero que no requiere mucho espacio o cálculo.

Cuando se detiene el efecto lento, los relojes todavía se están utilizando y se incrementan en un 100% del tiempo que realmente pasó.

Esto también podría funcionar para acelerar los hechizos.

@Sidar: veo dos opciones,

  1. Reloj interno por criatura. Para saber si la criatura está lista para atacar de nuevo: guarda la última vez que se usó cada ataque + tiempo de recarga y verifica si el reloj interno ya pasó ese tiempo.

  2. Un temporizador por ataque: sabes cuánto tiempo tarda el ataque en recargarse y simplemente configuras un temporizador y restas el tiempo que pasó * (1% de desaceleración) cada turno.

Personalmente prefiero evitar restar múltiples temporizadores individuales y usar un reloj interno para ahorrar tiempo y complejidad de procesamiento.

Realmente depende de las preferencias (no afecta tanto el rendimiento).

AturSams
fuente
La necesidad de relojes internos no es necesaria. Simplemente se reduce a un multiplicador que puede (de alguna manera) vincular a su objeto que aumenta o disminuye el producto de su dt (tiempo delta). Puede administrar los objetos por grupos o por cualquier medio. Creo que tu camino puede ser un poco excesivo. Pero bueno, si funciona ... entonces funciona.
Sidar
@Sidar Si evita esto, probablemente necesitará un reloj por ataque solo para cronometrar la recarga del ataque, la duración del hechizo y esas cosas. Al menos de esta manera, solo necesita actualizar un reloj y simplemente mantener el tiempo de 'última activación' para el restablecimiento de las propiedades.
AturSams
Sin embargo, su pregunta es sobre la desaceleración del entorno, excepto el jugador. Para mí, eso suena como la forma más simple de simplemente multiplicar el dt con un número menor que 1. Manteniéndolo como está para el jugador.
Sidar
Bueno, ralentizar los entornos incluye disminuir su velocidad de ataque y sus otras habilidades (ya que es un juego de rol), podría haber varias habilidades de la mafia que dependen del tiempo de recarga. Cura, beneficios, desventajas, hechizos, etc. Sin mencionar el tiempo de activación.
AturSams
2

Puede comenzar con una solución simple como la expuesta por tesselode o Mr Beast. Pero si comienzas a mezclar cosas complejas, es decir, un tiempo de bala mientras se lanza un hechizo de desaceleración, te quedarás atascado.

Le sugiero que implemente una jerarquía de reloj :

.
├── Main clock
│   └── UI clock
│   └── 3D clock
│       ├── GFX clock
│       └── Gameplay clock
│           └── Slowdown spell clock 01
│           └── Slowdown spell clock 02

Todo en su juego debe usar tiempos delta desde uno de los relojes: los efectos gráficos se ejecutan en el reloj GFX, la IA y la animación se ejecutan en el reloj del juego, las criaturas afectadas por un hechizo de desaceleración se ejecutan en un reloj de hechizo de desaceleración temporal, etc. Luego varias cosas afecta diferentes partes de su jerarquía: un hechizo de ralentización crea y afecta un reloj personalizado, mientras que un tiempo de bala afectará a toda la jerarquía del reloj 3D.

Laurent Couvidou
fuente
Gracias, esta es una idea importante. Sin embargo, creo que mantendré las ideas simples, ya que no tiene sentido en mi caso particular que ocurran múltiples efectos de desaceleración al mismo tiempo.
David Miler
1

Solo necesitas dos relojes diferentes en lugar de uno, uno para el tiempo relevante para el juego y otro "verdadero".

currentGameTime = 0;
gameSpeed = 1.0f;
[...]
currentApplicationTime = GetTime():
timeDelta = (currentApplicationTime - lastApplicationTime)*gameSpeed;
currentGameTime += timeDelta;
lastApplicationTime = currentApplicationTime;

Luego, simplemente puede cambiar gameSpeed ​​para acelerar (> 1) o ralentizar el tiempo (<1). Para que el jugador se mueva a una velocidad diferente, simplemente verifique si el tiempo se ralentiza o no.

API-Bestia
fuente