I am running into an issue where FixedUpdate is being called when Time.timeScale is 0.0f. This is also causing the physics step to advance by an additional step, causing my objects to move twice as fast for that FixedUpdate. What might be causing this and is there a way to ensure my objects do not move if Time.timeScale is set to 0.0f?
I am not manually adding any forces in any update with my objects. I am only using gravity, constant velocity, and animators that are set to animate with physics. Further, I tried an empty project and don’t have anything moving in my scene and I still am running into the issue where FixedUpdate is being called when Time.timeScale is 0.0f.
Because I set Time.timeScale to 0.0f, if I set Time.fixedDeltaTime to 0.02f * Time.timeScale then it makes an even greater amount of extra calls to FixedUpdate. If I set Time.fixedDeltaTime to float.MaxValue when Time.timeScale is 0.0f, it helps a little bit, but it eventually performs and extra call to FixedUpdate.
Edit: Also, I am only setting Time.timeScale to 1.0f or 0.0f.
When you see this extra call to FixedUpdate, what is your Time.time value?
If you happen to stop exactly on a FixedUpdate time (e.g. divisible by 0.02), I would expect there to be one more FixedUpdate call. That said, I’d be shocked if this happened consistently, unless you’re setting Time.timeScale to 0 in the first frame, when it’s 0 to begin with.
In the project that is empty, it is almost always divisible by 0.02, or very close to that. However, is my project it is not divisible boy 0.02. In one case, Time.time was 24.32667.
I am setting Time.timeScale to 0.0f every 3rd (or n-th) physics step.
If you’re only setting Time.timeScale in FixedUpdate, you should try setting it in the normal Update step or other non-fixed functions. FixedUpdate can be called multiple times in the same frame, and I don’t know what kind of behavior you can expect from setting timeScale during a FixedUpdate. Setting it outside FixedUpdate will take effect for the next frame’s FixedUpdates, which in theory should not happen if timeScale==0.
I set Time.timeScale to 0.0f in FixedUpdate and then reset it back to 1.0f in Update or at the end of the frame. I am essentially trying to freeze time in my FixedUpdate and then let the regular Update resume time after a given event has happened.
I think what’s happening here is this:
Unity starts a game frame. The “real time” value is 0.085234235 seconds.
Unity runs FixedUpdate repeatedly until it catches up to real time. It runs FixedUpdate for 0.00, 0.02, 0.04, 0.06, and 0.08.
On the third of these FixedUpdates, you’re setting Time.timeScale to 0. But, it’s still not caught up to “real time”. So even though “real time” is not advancing, physics time still has to catch up, and it will run FixedUpdate (and all physics) two more times (for the 0.06 and 0.08). These two are what’s causing the issues you’re seeing.
You may try increasing the fixed time step (to an arbitrarily large value, like 999) instead of decreasing it. This may make the engine think it has caught up to real time with its FixedUpdate’s. However, it’s possible this may not work depending on the details of how Unity coded this loop.
This is a bit of a dirty hack. It might be helpful to ask what your goal is? I ask because this seems really unusual to me:
I am essentially trying to output various camera snapshots at a constant frame rate. Because of the amount of data I want to output, I cannot do it in real time, so I wanted to freeze time every several physics updates to ensure that my objects are at their correct positions until the next frame is rendered.
I suppose another dirty hack is to add a “if (Time.timeScale == 0) return;” at the beginning of FixedUpdate, but like the above posters noted, it seems like you are breaking Unity when trying to change the time scale in FixedUpdate anyway.
Nevermind… Time.captureFramerate is trying to do what I was attempting with freezing time in FixedUpdate. Objects are still not moving at a constant velocity. For an object with a constant velocity of 5.0 m/s, in some frames, it is moving at 6.0 m/s and other frames at 3.0 m/s and 0.0 m/s. I need to ensure that the velocity between frames is accurate. Not sure how to resolve this now…
The only solution I can think of right now is… When FixedUpdate is called an extra time, record snapshots of every single moving object in the scene and then restore each object to its snapshot state in WaitForFixedUpdate.
You want FixedUpdate to be called as many times as it needs to. It’s an incremental function, so it won’t ever go further than it’s supposed to based on the amount of time that has passed since last frame. The “amount of time passed” or deltaTime is affect by TimeScale.
You’re trying to take screenshots according to your previous reply? I’m not even sure you need to stop time for this.
public class Example : MonoBehaviour
{
public float snapshotDelay;
public string filePath;
private WaitForSeconds snapshot;
private void Awake()
{
snapshot = new WaitForSeconds(snapshotDelay);
}
private IEnumerator Start()
{
while(enabled)
{
Application.CaptureScreenshot(filePath);
yield return snapshot;
}
}
}
Well, I am trying to output the image from an array of cameras, including depth image, motion vectors, etc., as well as outputting text data containing object poses and velocities.
I tried a simple test where I have my object’s velocity set at 5.0 m/s and I take screenshots every 1/30 seconds. When I record the velocity at each screenshot, it varies between 3.0 m/s and 6.0 m/s, and is never exactly 5.0 m/s. Also, if I don’t follow my solution above, FixedUpdate gets called an additional times trying to catch up to what Unity thinks the next Time.time value should be and ultimately moves my object further than I would expect it to. An example of this is when I tell my object to stop moving after 1 second. FixedUpdate ends up thinking that it needs to catch up to some time value that is past 1 second. The result of this is that my object moved over 6 meters, instead of 5 which it should have moved based on it’s velocity and the time I want it to stop at.