Search Unity

Rigidbodies experience huge changes in velocity if they are colliding when I change Time.timeScale

Discussion in 'Scripting' started by Quade81, Oct 23, 2014.

  1. Quade81

    Quade81

    Joined:
    Jul 30, 2012
    Posts:
    6
    I've tried to isolate my issue as much as possible, so I have a simple scene with with only one script that changes from regular speed to slow motion and back when you press space:
    Code (CSharp):
    1.     void Update()
    2.     {
    3.         if(Input.GetButtonDown("Jump"))
    4.         {
    5.             if(Time.timeScale == 1)
    6.                 Time.timeScale = 0.003f;
    7.             else Time.timeScale = 1;
    8.             Time.fixedDeltaTime = Time.timeScale * 0.02f;
    9.         }
    10.     }
    In slow motion, collisions cause much more bounce than at regular speed and it seems worse if the collision is taking place when I change time.


    And it's much worse with ragdolls...(you can skip to the middle of this video if you don't want to wait 20 seconds to see the issue)



    I realize that 0.003 is a very small time scale, but I have been able to reproduce the issue with a time scale as large as 0.1, while it isn't as extreme it is still noticeable.

    I have no idea where to go from here. I have been googling nonstop for 3 days and tried numerous things but nothing has worked. At this point, I willing to try any suggestions even if I've already tried them so throw any idea you've got my way.
     
  2. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    I don't know if this would work as I would never dream of changing the fixed time step during runtime, but here's what comes to mind:

    You might try saving the velocities (both linear and angular) right when you change the time step size. I.e., at the beginning of the FixedUpdate() call immediately following the time step change in Update(), save the rigid body velocities. On the next call to FixedUpdate(), reassign the velocities to what they were at the beginning of the step before it. Don't update the positions, just change the velocities. I don't know if it'll work, but it's at least an idea.

    The reason this comes to mind as a possiblity for a solution is because of the years of work I did writing my own physics engine used in VRC Pro. When it came to computing collision response impulses, one component of all that was an extra impulse that was there just to remove penetration. This would easily be enough to send objects flying and doing crazy things even without a time step change. What I did there was save the angular and linear momenta of the bodies as it would exist without that extra impulse. On the next time step the bodies would go to potentially huge velocities in order to remove penetration, but it only lasted for 1/250th of a second (my time step was very small for this high fidelity racing simulation). After the objects had moved and rotated for one physics step, the momenta were restored back to what they were with the extra impulse removed. In other words, I gave it a huge kick and then subtracted part of the effects of that kick back out on the next step.

    In effect, it added a huge impulse, then on the next step it removed the momentum increase that was caused by it. So an object could pop out of a wall at 1000 mph but it would immediately return to "normal bounce speed," so to speak. I'm thinking maybe a similar approach might work in your case. You don't have access to angular and linear momentum directly in the Unity engine unfortunately, so you might have to make do just using the velocities.
     
  3. Quade81

    Quade81

    Joined:
    Jul 30, 2012
    Posts:
    6
    I have tried this and I couldn't get it to work as I wanted. I'll try it again when I get home, but, it isn't only when I change the time scale. It also happens sometimes when a collision occurs while the time is running at the slower speed.
     
  4. Quade81

    Quade81

    Joined:
    Jul 30, 2012
    Posts:
    6
    I've only tested it with a cube, but I think I may have solved the issue. Todd, what you said about never changing the fixed time step at runtime got me thinking. The original reason I did that was to keep the physics updates from being choppy at really low speeds. I realized I could do this with the rigidbody interpolate instead. So I turned that on and removed the fixedDeltaTime change from my script and it seems to have done the trick. I'll update this when I get home and can test it with my ragdolls
     
  5. image28

    image28

    Joined:
    Jul 17, 2013
    Posts:
    457
    You could try changing isKinematic before adjusting the timescale and then next update turning it back off...
     
  6. Quade81

    Quade81

    Joined:
    Jul 30, 2012
    Posts:
    6
    I thought about that but wouldn't I lose all the current momentum? Also It happens when ever the time scale is lowered not just the frame when I actually change it.
     
  7. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,079
    Sounds good. Please keep me posted, I'm curious how it goes. Maybe I may run into the problem some day and remember this...
     
  8. Quade81

    Quade81

    Joined:
    Jul 30, 2012
    Posts:
    6
    Setting my rigidbodies to interpolate instead of changing Time.fixedDeltaTime did solve the issue, however it brought on a few more. Now when I fire an arrow in slow motion it stays in one place until the next fixed time step comes around and every time there is a FixedUpdate my ragdolls arms jump for a frame... Oh the joys of gamedev
     
    ohohgames likes this.
  9. bitHussar

    bitHussar

    Joined:
    Jan 9, 2016
    Posts:
    33
    I know it's an old thread but did you manage to fix this? I'm struggling with the same issue as well...
     
  10. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,195
    I created a thread on this same topic a while back:

    https://forum.unity.com/threads/rig...assive-force-when-entering-in-slow-mo.751352/

    I never found a true solution (I still can't instantly change timescale without weird physics behavior). However, I found I can gradually change timescale over the course of .2 seconds or so, without much issue. That won't work for everyone, as this will look like a kind of weird time dilation. But maybe that effect is okay, or you could hide the game behind some UI while changing timescale, if that could possibly work for you game.