Ralentización del tiempo para objetos específicos en Unity

¿Alguna vez has jugado uno de esos juegos en los que puedes ralentizar el tiempo mientras te mueves a velocidad normal? ¿Alguna vez has pensado en poder hacer eso en tu juego? Eso sería genial, ¿verdad? Hay una manera de hacer precisamente eso con Unity Engine, aunque requiere algo de trabajo.

Para cualquier movimiento independiente de la velocidad de fotogramas calculado usando el tiempo delta y el valor de la escala de tiempo, se puede lograr ralentizar el tiempo mientras se mantienen algunos objetos a la misma velocidad configurando la escala de tiempo entre 0 y 1 y compensando el tiempo ralentizado por esa cantidad. Usar el valor de tiempo sin escalar también puede lograr esto.

Eso puede sonar muy confuso para ti, lo sé. Sigue leyendo y te daré algunos ejemplos y cómo lograr ralentizar el tiempo mientras mantienes algunos objetos intactos de diferentes maneras.

Tenga en cuenta que estos métodos no son perfectos y que existen ventajas y desventajas para cada uno de ellos. Dependiendo de lo que quieras lograr y de cómo funcione tu juego, es posible que no puedas ralentizar el tiempo a la perfección o que no lo hagas en absoluto. Utiliza las que más se adapten a tus necesidades.

Tabla de contenido

Compensación de la escala de tiempo

Una de las formas más fáciles de hacer que un objeto se mueva a una velocidad normal mientras el tiempo se ralentiza es compensar el tiempo ralentizado con una mayor velocidad de movimiento.

Digamos que tenemos un objeto que se mueve a lo largo del eje X con una velocidad de 5 unidades por segundo y el valor de la escala de tiempo es 0,5:

private float speed = 5f; private void Start() { Time.timeScale = 0.5f; } private void Update() { float newXPosition = transform.position.x + (speed * Time.deltaTime); transform.position = new Vector2(newXPosition, transform.position.y); }

Code language: C# (cs)

Según el código anterior, el objeto se moverá a una velocidad de solo 2,5 unidades por segundo en lugar de 5 unidades por segundo como pretendíamos. Esto se debe a que el tiempo se ralentiza a la mitad.

Entonces, ¿cómo hacemos que se mueva a 5 unidades por segundo mientras la escala de tiempo aún se reduce a la mitad?

Podemos hacer esto fácilmente dividiendo la velocidad del objeto por la escala de tiempo, así:

private float speed = 5f; private void Start() { Time.timeScale = 0.5f; } private void Update() { float offsettedSpeed = speed / Time.timeScale; float newXPosition = transform.position.x + (offsettedSpeed * Time.deltaTime); transform.position = new Vector2(newXPosition, transform.position.y); }

Code language: PHP (php)

Al dividir la velocidad del objeto por la escala de tiempo, efectivamente haces que el objeto vaya más rápido, pero se ralentiza por la escala de tiempo reducida, lo que hace que se mueva a la velocidad normal.

Déjame explicarte el cálculo paso a paso:

  • El objeto se mueve a 5 unidades por segundo cuando el tiempo avanza a velocidad normal.
  • Cuando la escala de tiempo se establece en la mitad de la velocidad normal, el objeto también se mueve a la mitad de su velocidad, que es de 2,5 unidades por segundo.
  • Al dividir el valor de la velocidad por la escala de tiempo, hacemos que el objeto se mueva más rápido: 5 / 0.5 = 10 unidades por segundo.
  • Pero debido a que el tiempo se ralentiza a la mitad, la velocidad también se reduce a la mitad, volviendo a 5 unidades por segundo.
  • Lo bueno de hacerlo de esta manera es que no tienes que implementar ningún paso adicional para que funcione también cuando el tiempo se acelera o cuando el tiempo vuelve a la velocidad normal. Bastante ingenioso.

    Uso de tiempo sin escalar

    ¡Hay otra forma de hacer que un objeto se mueva a una velocidad normal cuando el tiempo se ralentiza y es ignorar la escala de tiempo!

    Puede ignorar la escala de tiempo utilizando Time.unscaledDeltaTime en lugar de Time.deltaTime al calcular la posición de un objeto.

    Time.unscaledDeltaTime ignora por completo el valor de la escala de tiempo y utiliza el tiempo del mundo real en su lugar.

    private float speed = 10f; public bool useDeltaTime = true; private void Start() { Time.timeScale = 0.5f; ShouldRespectTimeScale(false); } private void Update() { float nextPosition; if (useDeltaTime) { nextPosition = transform.position.x + (speed * Time.deltaTime); } else { nextPosition = transform.position.x + (speed * Time.unscaledDeltaTime); } transform.position = new Vector2(nextPosition, transform.position.y); } public void ShouldRespectTimeScale(bool shouldRespect) { useDeltaTime = shouldRespect; }

    Code language: PHP (php)

    Del ejemplo anterior, verificamos si queremos ignorar la escala de tiempo o no, y luego calculamos la siguiente posición a la que el objeto debe moverse en función de eso. Eso es todo. Muy simple.

    Compensación de los parámetros de RigidBody

    Para los movimientos que utilizan RigidBody 2D, no hay formas sencillas de hacerlo, ya que todo el componente está vinculado al motor de física.

    Se puede ignorar la escala de tiempo compensando los valores de velocidad, escala de gravedad y masa, entre otras propiedades del componente 2D RigidBody.

    Por ejemplo, si desea hacer que un objeto se vea como si se moviera a su velocidad normal incluso cuando el tiempo se ralentiza a la mitad, tendrá que compensar el movimiento ralentizado aumentando el valor de la velocidad en la cantidad de pérdida.

    private float velocity = 15f; private RigidBody2D rb; private void Start() { Time.timeScale = 0.5f; rb = GetComponent<RigidBody2D>(); rb.velocity = new Vector2(velocity / Time.timeScale, rb.velocity.y); }

    Code language: C# (cs)

    El ejemplo anterior establece la velocidad a lo largo del eje X del objeto en 15 dividido por la escala de tiempo actual. Esto hará que el objeto se mueva visualmente a la misma velocidad incluso si la escala de tiempo cambia de alguna manera.

    También puedes usar este mismo truco con la escala de gravedad:

    private float velocity = 15f; private float defaultGravityScale = 1f; private RigidBody2D rb; private void Start() { Time.timeScale = 0.5f; rb = GetComponent<RigidBody2D>(); rb.velocity = new Vector2(velocity / Time.timeScale, rb.velocity.y); rb.gravityScale = defaultGravityScale / Time.timeScale; }

    Code language: C# (cs)

    Si la gravedad o el movimiento se sienten extraños, es posible que deba ajustar los valores de arrastre y tal vez la masa del objeto hasta que se sienta bien, pero en general, esto debería funcionar.

    En cuanto a RigidBody 3D, puede hacer lo mismo con el valor de velocidad, pero el valor de gravedad es un poco diferente y no puede cambiarlo para objetos individuales. Es mejor escribir su propio guión de gravedad si planea hacer que algunos objetos no se vean afectados por la escala de tiempo.

    Evitar que la animación se vea afectada por la escala de tiempo

    La animación también es otro problema cuando se trata de usar la escala de tiempo. Incluso si podemos hacer que el movimiento de un objeto no se vea afectado por Time.timeScale, la animación seguirá viéndose afectada.

    Es posible hacer que la animación no se vea afectada por la escala de tiempo global. Esto se puede lograr configurando la propiedad Modo de actualización del componente Animator en Tiempo sin escalar.

    Esto hará que la animación ignore la escala de tiempo global y se reproduzca a una velocidad normal.

    También puede lograr el mismo resultado mediante programación mediante el uso de un script, en caso de que desee poder controlar qué se ralentiza y qué no en tiempo de ejecución.

    public void AnimateIgnoreTimeScale() { Animator anim = GetComponent<Animator>(); anim.updateMode = AnimatorUpdateMode.UnscaledTime; }

    Code language: C# (cs)

    Hay 3 tipos de modos de actualización que puede usar:

    • AnimatorUpdateMode.Normal: se actualiza normalmente, afectado por Time.timeScale.
    • AnimatorUpdateMode.UnscaledTime: actualizaciones independientes de Time.timeScale.
    • AnimatorUpdateMode.AnimatePhysics: se actualiza durante el ciclo de física para que la animación se sincronice con el motor de física. Este modo de actualización también se ve afectado por Time.timeScale.

    El modo de tiempo sin escala también funciona cuando la escala de tiempo se establece en 0, lo que hace que el tiempo del juego se detenga por completo.

    Eso es todo de mi parte. Hacer que algunos objetos no se vean afectados por la escala de tiempo puede ser complicado y no todas las soluciones funcionan en todas las situaciones. Elige con cuidado y piensa en lo que necesita tu juego.

    Con suerte, este artículo es de alguna utilidad para usted. Deje un comentario si tiene alguna pregunta o si tiene alguna sugerencia.

    ¡Salud!

    Atribución

    Ícono lento hecho por Freepik de www.flaticon.com