I’d like to use Time.timeScale to speed up, slow down, and pause my game, but the problem is that this makes certain scripts behave in unintended ways. For instance, my camera control script uses Time.deltaTime in order to rotate and move it around smoothly, and I don’t want the current timeScale to change its speed or pause it. Is there a simple way to get a value that’d be the equivalent of Time.deltaTime if Time.timeScale were 1?
I’ve searched for quite a while for an answer but it seems like the solution seems to be creating my own timeScale, plugging it in everywhere I need it, and ignoring Unity’s Time.timeScale entirely, which is pretty annoying. People have suggested replacing instances of “* Time.deltaTime” with “* (Time.deltaTime / Time.timeScale)”, but that’s just a division by zero error waiting to happen.
So for those scripts like your camera script that you don’t want to slow down or stop … just record the delta time yourself by keeping track of the time the last frame subtract from the time of the current frame.
So does every script that needs to be independent of timeScale needs to individually track previous realTimeSinceStartup (since it will vary slightly for each)? And I suppose they’ll need special logic in there if the script’s Update isn’t always going to be called every frame since “realTimeSinceStartup - previousRealTimeSinceStartup” is not guaranteed to be the same as deltaTime’s “time in seconds it took to complete the last frame”.
It’d just be so much cleaner if Unity provided a way to get the REAL deltaTime instead of forcing timeScale on everything related to the delta. But I suppose that’s the best we can do?
Just make a function that takes timeScale into account (use Time.deltaTime / Time.timeScale but check for 0 first), and use that instead of Time.deltaTime.
Checking for zero first is easy. The harder part is deciding what we’ll pretend deltaTime was in the case that it was zero. It seems like I’m going to have to check against realTimeSinceStartup in that case, which brings on the issues I mentioned about that before. I guess I’ll end up having a special timekeeper GameObject whose Update is always called (no disabling that component script). I’m still seeing a potential problem with that, though: There’s no guarantee that the timekeeper’s Update will be called before the other objects’ (and I really don’t want to make all of the others use LateUpdate if possible since I want to be able to guarantee those objects’ Update calls run before the updates certain other scripts use). Perhaps it’s the best we can do and I’ll just have to deal with the delta possibly being a bit off once in a while; it might not even be noticeable on the users’ end.
All that said, what do you think of this solution?
public class Timekeeper : MonoBehaviour {
private float prevRealTime;
private float thisRealTime;
void Update () {
prevRealTime = thisRealTime;
thisRealTime = Time.realtimeSinceStartup;
}
public float deltaTime {
get {
if (Time.timeScale > 0f) return Time.deltaTime / Time.timeScale;
return Time.realtimeSinceStartup - prevRealTime; // Checks realtimeSinceStartup again because it may have changed since Update was called
}
}
}
EDIT: This post is wrong. There was a bug in my code. Keep reading the thread past this.
Time.unscaledDeltaTime actually is still affected and changed by Time.timeScale. I just tried it out. It appears that Time.realtimeSinceStartup is the only solution.
unscaledDeltaTime isn’t affected by timeScale. Even if it was, realtimeSinceStartup isn’t a real solution since the precision degrades too much after a few days of runtime. See my post above for a better solution, or just use unscaledDeltaTime since it does work.
You are right. I was wrong. I just did another test and verified so. My previous test had a bug in it’s code. Thanks so much! I will edit my previous reply to not mislead anyone.