F

drag_factor and high FPS

FrankTR

I was REALLY struggling with getting this to work.
I wrote, rewrote, checked and double checked the code, but my ship would still instantly turn.
Then I just cut and pasted the code, but still the same issue, ship turned instantly.

In the end it turned out that the drag_factor and/or my PC's FPS that was the issue. The text says to keep drag_factor somewhere between 0.01 and 0.3. I had to tune it WAY down to around 0.0005. That made the ship steer smoothly. 

When I dug down into it, I actually saw my CPU go all the way to 76% when I ran the scene. That looked very high and told me it probably draws a lot of frames. Turns out it drew 1500+ FPS. 

I then went to Project Settings -> Debug -> Settings and set Force FPS to 60. That let me use drag_factor of about 0.05. But that seems to be "cheating".

How could I get around this in the code, since I wouldn't know if my game would be running on a potato-PC or an i9 with a 4090-card?

I have a pretty OK computer with an i5-13600KF and a RTX3070, but isn't that what using the delta-value should counter? Should we also multiply drag_factor by delta?

It seems to work when I do that, but then I have to up drag_factor to about 2.0, and the GPU really works hard and puts out loads of FPS again. It shouldn't have to run at full blast for this "game".

PS!
I'm sorry that I have rewritten this about 17 times, but I've tried to make it a little clearer, as what I wrote initially was all over the place.

  • Nathan Lovato replied
    Solution

    The text says to keep drag_factor somewhere between 0.01 and 0.3. I had to tune it WAY down to around 0.0005. That made the ship steer smoothly. 

    ...

    I then went to Project Settings -> Debug -> Settings and set Force FPS to 60. That let me use drag_factor of about 0.05. But that seems to be "cheating".


    This suggests to me that your code might be framerate-dependent. If the code is not framerate-dependent, changing the frames per second should not change how the game behaves.

    Could you please check the line where we change the position multiplies the velocity by delta in your code ?

    It should look like this :

    position += velocity * delta

    If this line of code was missing delta, the behavior you observed regarding the drag_factor is normal.

    If that's not the issue, could you please copy and paste your complete code in a reply to this post, so that I can inspect it and see if something else is going on?


    Regarding the other issue of the framerate and CPU usage, it is most likely that something is preventing VSync from working. Godot is set to, by default, synchronize with the refresh rate of your display. But that's only if your graphics card supports VSync (your graphics card does support it) and I guess your graphics settings outside of Godot allow VSync.

    When VSync is active, the framerate in Godot will be limited to that of your display. But when it's turned off, by default, the engine will render as many frames per second as possible (using a lot of CPU and GPU power in the process).


    I hope this helps!

    1 love
  • F
    FrankTR replied

    Firstly, thanks for the reply!

    Vsync was my error
    The problem with vSync not working was my wrong. Somehow, that had been disabled in the Nvidia control panel settings. I enabled that, and vSync now works. So if I run Godot with vSync enabled, it works, and the ship steers accelerates and decelerates as it should. If I turn it off, it still misbehaves.

    Code still misbehaving
    To avoid it being something with my code, I now took the code from the course and pasted it directly, but without vsync it still behaves in the same manner I described.

    extends Sprite
    
    var boost_speed := 1500.0
    var normal_speed := 600.0
    var max_speed := normal_speed
    var velocity := Vector2.ZERO
    var drag_factor := 0.05
    func _process(delta: float) -> void:
     var direction := Vector2.ZERO
     direction.x = Input.get_axis("move_left", "move_right")
     direction.y = Input.get_axis("move_up", "move_down")
     if direction.length() > 1.0:
      direction = direction.normalized()
     if Input.is_action_just_pressed("boost"):
      max_speed = boost_speed
      get_node("Timer").start()
     var desired_velocity := max_speed * direction
     var steering_vector := desired_velocity - velocity
     velocity += steering_vector * drag_factor
     position += velocity * delta
     rotation = velocity.angle()
    func _on_Timer_timeout() -> void:
     max_speed = normal_speed

    I did this short video to show what happens with vSync on and off.

    PS!
    For fun I also ran the same in Godot v4.1.2 and it's the same behaviour there.
    1 love
  • Nathan Lovato replied

    Thanks for the video! I see, you had the right intuition, we should multiply drag_factor by delta for extreme cases like these, it's definitely showing framerate-dependent behavior. So using a drag_factor of maybe 2.0 or something like this and multiplying it by delta should give you consistent behavior.

    Great catch! It's an issue that's hard to spot even if the framerate drops, but with this high FPS it makes a world of a difference.

    3 loves