Currently, as of 12/19/24, DeltaTime (as seen in events like RunService.Stepped) is extremely unreliable at lower framerates.
DeltaTime in other engines is often used to make framerate-independent game mechanics. However, DeltaTime on Roblox cannot be used reliably for this purpose, as it provides inaccurate values at lower framerates.
Steps to reproduce:
Open the repro place file attached to this bug report
Run a playsolo session at 144 FPS.
Hold the LeftShift key. Observe that after 2 seconds, a os.clock() diff is printed and it has a value near 2.
Set studio’s framerate to 20 FPS. Repeat step 3.
Observe that again, after 2 seconds an os.clock() diff is printed with a value near 2.
Set studio’s framerate to 12 FPS. Repeat step 3.
Observe that this time, the os.clock() diff is printed with a value near 3.
Interestingly, if you switch the Stepped out for RenderStepped, the provided DeltaTime parameter does not suffer from this inaccuracy at low framerates.
id assume its because “The Stepped event (equivalent to PreSimulation) fires every frame, prior to the physics simulation.”
while the RenderStepped event runs right before a frame is rendered.
You can see that RenderStepped is just before everything basically so its deltatime should always be stable.
as for Stepped, its in the middle of everything, so thats probably why its deltatime varies, im not an expert though so i could just be spreading bs.
instead of using runservice, you can try experimenting with tick() to create frame-independent loops.
So, do the people replying to this thread not understand how frames work or something? Or do they not understand that the sum of the delta times of frames rendered over any two second period should be… two?
If you’d read the bug report you would know the issue isn’t with deltatimes fluctuating, it’s with the reported deltatimes being inaccurate. Regardless of framerate, the sum of the deltatimes between n frames in a 2 second period should be… ~2 seconds.
Are you using a plugin to cap your framerate, or am I just looking at the wrong place in settings?
Anyway, from my understanding, Stepped reports the amount of physics time elapsed per frame rather than the actual time duration (which is what RenderStepped reports and it’s why the problem is less prevalent there).
What you’re seeing would suggest that the engine is actually running more physics steps per second at lower framerates than it would at normal framerates, which should show up in the microprofiler. While it’s still certainly a bug, it might also confirm some hunches I’ve had…
I’ve done several tests, and I haven’t seen this occurring. I’ve printed output every time a RunService event fires, and they’ve always fired sequentially together. There were no instances of PostSimulation or Heartbeat being printed on their own. I also checked the microprofiler and did not see anything.
I’ve done some further testing. If you sum up the total deltatimes for Stepped, Heartbeat and RenderStepped for two seconds the Stepped sum ends up being over a full second behind at low framerates:
Thank you for the detailed report, and apologies for the delayed response from us! First, note that for PreSimulation (which has replaced Stepped), the delta time parameter is the amount of time that the current frame will advance the physics simulation, not the time elapsed since the last frame. (Note also that this does not take into account throttling).
Within one rendered frame, the physics is in general updated/advanced multiple times. This physics time step size is somewhat independent of the rendered framerate, for concreteness lets consider the Fixed stepping method, where the time step is set as 1/240 = 0.0041667 seconds. So, for example, at a framerate of 30 fps (one frame advances the game by 1/30 = 0.0333 seconds) the physics engine may take 8 steps to advance the physics in real time. In this case, however, the deltaTimeSim from PreSimulation will still return 1/30 = 0.0333, i.e. it returns the total amount of time advanced, not the individual time step size.
Now lets consider the case of a very low framerate, say 5 fps. Then one frame covers 0.2 seconds, which would correspond to 48 physics steps. However, the engine has a limit on the number of physics steps that can be performed during one frame (if you pause the microprofiler in the repro you can see it is 16). I believe this was decided on long ago for performance reasons. Essentially for very low frame rates we abandon the goal of keeping the physics running in real time. The deltaTimeSim from PreSimulation will reflect this choice, meaning that deltaTimeSim will be smaller than the time between 2 frames. In our example running at 5 fps, the deltaTimeSim will be 16*0.0041667 = 0.06667 seconds, instead of 0.2 seconds. This is why the counters are off in your examples when the framerate is greatly limited.
As you noticed, the DeltaTime associated with PreRenderis actually the time between frames, which is why it does not have the same character.
Hopefully that is helpful, and apologies again for the delay.
Can we get some of this clarification on the documentation? There is very little clarification that deltatime actually behaves differently in these ways on there, and evidently it is a very easy mistake to confuse the meanings of the values provided by these RunService events.
I’ve read over the RunService docs many times and never got the impression that these actually had differing behavior with effects like this. This would just be a nice thing to have, even if it’s brief