Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

AddForce adds less force when fixedTimeStep is lowered?

Discussion in 'Physics' started by dgoyette, Aug 17, 2018.

  1. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,120
    I'm having an issue where when I try to run in "slow motion", my forces aren't behaving as expected.

    In my game, time occasionally slows down when certain events occur. I'm using the following code to make that happen:

    Code (CSharp):
    1.         public static void SetTimeScale(float timeScale)
    2.         {
    3.             Time.timeScale = timeScale;
    4.             if (Time.timeScale == 0)
    5.             {
    6.                 Time.fixedDeltaTime = UnityConstants.Time.FixedTimeStep;
    7.             }
    8.             else
    9.             {
    10.                 // Min this out at .1f, as going all the way down to near 0 triggers huge physics load for a frame or two.
    11.                 Time.fixedDeltaTime = UnityConstants.Time.FixedTimeStep * Mathf.Max(0.1f, Time.timeScale);
    12.             }
    13.         }
    I'm adjusting fixedDeltaTime here because I want smooth physics when the game is slower. (This is an approach I've see elsewhere). This looks good, and I get nice smooth motion when running the game slowly. However, if I try to AddForce to objects when in slow motion, not enough force is applied. Specifically, my player can no longer jump very high.

    Here's my jump code, which is triggered exactly once per jump.

    Code (CSharp):
    1.                     var force = transform.up * _rigidbodyKinematicController.RigidbodyMovementSettings.JumpStrength * _rigidbody.mass * (_godMode ? 4 : 1);
    2.  
    3.                     // When timeScale isn't 1, we need to adjust the forces due to the way physics behaves differently in slow-mo.
    4.                     // If we don't do this, the player's jump will be too high or low depending on whether whether time is
    5.                     // moving faster or slower than usual.
    6.                     //if (Time.fixedDeltaTime > 0 && Time.fixedDeltaTime != UnityConstants.Time.FixedTimeStep)
    7.                     //{
    8.                     //    force *= UnityConstants.Time.FixedTimeStep / Time.fixedDeltaTime;
    9.                     //}
    10.  
    11.                     _rigidbody.AddForce(force);
    The original version of this was simple: up * mass * jump strength, then send the force to AddForce. However, when running at a slower timescale (0.25f, for example), this doesn't jump very high. So I added the commented-out code to adjust the force based on the current fixedDeltaTime.

    Although this seems to work, I'm I'm not confident it's accurate. I also don't want to have to worry about adjusting every AddForce call in my game based on timescale.

    I feel like I must be missing something here. Based on my code to slow down time, I would have expected the physics to behave identically as it would at normal time scale, with everything just being drawn out over a longer period. Instead, it feels like AddForce is adding only 1/4 of the normal force when time is dlowed down to 25%.

    Any ideas what I'm doing wrong here?
     
  2. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    I've noticed that tinkering with the timestep can cause this sort of thing with physics as well. I was doing a slow motion effect for a driving game, and noticed that when lowering the timestep that the physics of vehicles (although built in such a way that it should behave the same regardless) still sort of acted slightly different at the faster timestep.

    This has something to do with the guts of PhysX (and probably box2d as well) not being perfectly lockstep accurate at any speed, and being kind of generalized for performance reasons, so the physics having more frequent checks at the higher timestep means that things play out differently on the bodies and the drag and forces act differently against them... at least that is what I think is going on behind the scenes... perhaps somebody has more accurate info out there.

    I don't think that your going to find a straightforward solution - and are gonna kind of have to hack it a little, and just use some magic numbers to add/remove some of the value depending on the change in timestep (more force apparently will be needed in the case of your jump, but other times you might find that you need less force).

    Sorry I don't have a better answer!
     
  3. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,120
    Thanks for the help. Looking into this further, I think I understand what's going on, assuming that Unity's Physics engine works like "real life" to some degree.

    First, I noticed that I wasn't having issues with all uses of AddForce. For example, the forces I'm using on my character controller to walk around seemed to behave correctly regardless of timescale. It seems that it's only the one-off uses of AddForce (those forces not applied repeatedly by FixedUpdate) that are misbehaving. I think this probably makes sense to me, though that depends on whether Unity works as follows:

    My understanding is that for one-off use of AddForce on a rigidbody, the amount of force being applied entirely depends on the fixedTimeStep. It's something like: "Over the course of the next N seconds, apply M force per second". Basically, "Apply M force per second until the next FixedUpdate is called". If N changes (because the fixedTimeStep is changed), while M remains the same, less time is spent applying force to the object, because the next FixedUpdate happens sooner.

    For my AddForce usage within FixedUpdate calls, things work fine because while the timestep might be occurring twice as often, the duration of each FixedUpdate is half as long, equaling out. But for the one-off AddForce calls (jumping, explosions, punching, etc), I'll need to modify the force based on the fixedTimeStep.

    I'd be happy to be corrected on any of these details.
     
  4. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,434
    The problem is here. These forces are not misbehaving, they're behaving as intended.

    This is the misunderstanding. The correct description is: "Over the course of the next N seconds, apply M force" (not "per second").

    This means that a force M will be applied during N seconds exactly. Thus, if you make N smaller the force will be applied during less time, hence the different behavior.

    What you need to do in those cases is applying impulses. Addforce with ForceMode.Impulse or ForceMode.VelocityChange will cause a one-off sudden velocity change, being always the same effect regardless the time step.

    https://docs.unity3d.com/ScriptReference/ForceMode.html
     
    Last edited: Sep 14, 2019
    Sanguinax and MD_Reptile like this.
  5. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,120
    Ah, got it. That makes complete sense. I've rewritten my jump method such that it applies Impulse force, and my force calculation no longer incorporates the player's mass (since Impulse takes mass into account internally), and I get consistent jump height regardless of timescale.

    Thanks very much for clearing this up.
     
    Edy likes this.
  6. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,663
    Very cool, thanks for the info edy, I may revisit the problems I was having with timescale now, and see if I can wrap my head around it :)
     
    Edy likes this.
  7. LeHombreDeZbragl

    LeHombreDeZbragl

    Joined:
    Jan 31, 2021
    Posts:
    3
    Thanks Edy, works perfectly now.
     
  8. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,434