Hello, I have a problem with this script. Basically, my implementation is when the player picks up an orb (where I refer to it as slowOrb), it should slow the time down by the duration stored in the slowdownDuration variable. The function did work previously, but now I am having trouble. Any ideas of things that I can check in the Editor? Is there any improvement to my code required? Version 2020.1.3f1. Thank you in advance!
using System.Collections;
using UnityEngine;
public class SlowTime : MonoBehaviour
{
float slowdownFactor = 0.3f;
float slowdownDuration = 2f;
public Rigidbody2D slowOrbMove;
public float xDirectionVelocity, yDirectionVelocity;
void Start()
{
slowOrbMove.velocity = new Vector2(xDirectionVelocity, yDirectionVelocity * -1);
}
void OnTriggerEnter2D(Collider2D slowOrbCollision)
{
if (slowOrbCollision.gameObject.CompareTag("Player"))
{
StartCoroutine(SlowdownTime());
Destroy(gameObject);
}
}
public IEnumerator SlowdownTime()
{
Time.timeScale = slowdownFactor;
yield return new WaitForSecondsRealtime(slowdownDuration);
Time.timeScale = 1f;
}
}
@WeeSynDyr - Using a Coroutine to achieve the slow-motion effect, is a great start. The problem seems to be with the way Time.timeScale is being reset.
In your code, you’ve used WaitForSecondsRealtime in the Coroutine, which waits for a given number of seconds in real time, regardless of whether or not the time scale is set to zero. This means it isn’t affected by Time.timeScale. However, when the Time.timeScale is lowered, your Coroutine might be getting interrupted or not completing its duration as expected.
A better way to deal with this is by using a “time remaining” style countdown within your Coroutine. This way, you’re not relying on WaitForSecondsRealtime, but rather on the Time.unscaledDeltaTime which also isn’t affected by Time.timeScale.
public IEnumerator SlowdownTime()
{
Time.timeScale = slowdownFactor;
float timeRemaining = slowdownDuration;
while(timeRemaining > 0)
{
timeRemaining -= Time.unscaledDeltaTime;
yield return null;
}
Time.timeScale = 1f;
}
In this version, timeRemaining is set to the slowdownDuration. Each frame, we subtract the real time that passed since the last frame from timeRemaining, and when it reaches zero or below, we set Time.timeScale back to 1. This approach should be more reliable and less prone to the issues that might be interrupting your Coroutine.
Remember to check in the editor if the script is reaching the end of the Coroutine. You can do this by setting a debug log after Time.timeScale is set back to 1
Time.timeScale = 1f;
Debug.Log("Time Scale is set back to normal");