godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.88k stars 20.15k forks source link

delta time in _process() is incorrect (never lower than ~0.11) at low frame rates #94632

Open simonschreibt-code opened 1 month ago

simonschreibt-code commented 1 month ago

Tested versions

v4.2.2.stable.official [15073afe3]

System information

Windows 10, v4.2.2.stable.official [15073afe3]

Issue description

When I spawn many enemies and make the frame rate drop (intentionally), I noticed that the given delta value never goes below ~0.11 which means it will never show a value below 6-7 FPS.

Calculating the time manually by using Time.get_ticks_msec() works very well, though.

VIDEO explaining the issue: https://youtu.be/FkTF7sDQMME?si=9lPKdSul_MELgulX

Code Example

func _process(delta : float) -> void:

❌Does not work

func _process(delta : float) -> void:

    text = str(int(1.0 / delta))

✔Works

func _process(delta : float) -> void:

    time_before = Time.get_ticks_msec() - time_after
    time_after = Time.get_ticks_msec()
    real_delta = time_before * 0.001

    text = str(int(1.0 / real_delta))

Steps to reproduce

  1. Open the project
  2. Open fps.gd
  3. Change line 17 from text = str(int(1.0 / real_delta)) to text = str(int(1.0 / delta)) (to disable my fix and see the bad behavior)
  4. Start the project (F5)
  5. Click quickly several times on the "spawn" button to create many enemies which will drop the frame rate quickly

You will see that the FPS never goes below 6-7 even though clearly the game renders only one frame evera 2-3 seconds.

Minimal reproduction project (MRP)

process_delta_time_issue_at_low_fps.zip

Calinou commented 1 month ago

If framerate drops lower than physics_ticks_per_second / max_physics_steps_per_frame (60.0 / 8.0 = 7.5 FPS by default), the entire game (both process and physics process) will intentionally slow down to prevent "spiral of death" performance issues. This means the delta value will be higher than it would originally be.

You can adjust the Physics Ticks per Second and Max Physics Steps per Frame project settings to control this behavior.

You will see that the FPS never goes below 6-7 even though clearly the game renders only one frame evera 2-3 seconds.

Use Engine.get_frames_per_second() to measure FPS to avoid this quirk, or use the Time singleton as you did. If you need smoother FPS display, https://github.com/godotengine/godot/pull/63356 would address this out of the box.

simonschreibt-code commented 1 month ago

Thank you very much for the explanation! ❤