Search Unity

Bug Obstacle rotation speed problem on slower PC

Discussion in 'Scripting' started by PatD17th, Jan 30, 2023.

  1. PatD17th

    PatD17th

    Joined:
    Mar 27, 2013
    Posts:
    15
    Hey,
    I have been bothered by one crucial bug with rotating obstacle and it's speed. I think it has to be something with frame count on weaker machines. Whenever Pc can't handle the game (for example Intel HD 520) obstacle speeds up slower and rotates slower which prevents player from jumping above obstacles and can outrun them in circles.

    This problem is weird cause obstacle is using Time.DeltaTime which should solve this issue in the first place.

    The rotation script:
    Code (CSharp):
    1. public class ObstacleRotate : MonoBehaviour
    2. {
    3.     [SerializeField] private float _rotationSpeed;
    4.     [SerializeField] private float _minSpeed = 0f;
    5.     [SerializeField] private float _maxSpeed = 10f;
    6.     [SerializeField] private float _currentSpeed;
    7.  
    8.     private IEnumerator Start()  
    9.     {
    10.         var currentTime = 0f;    
    11.         while (_currentSpeed < _maxSpeed)
    12.         {
    13.             currentTime += Time.deltaTime;
    14.             _currentSpeed = Mathf.Clamp(_rotationSpeed * currentTime, _minSpeed, _maxSpeed);  //"_currentSpeed" = clamped value of rotationSpeed with min max values.
    15.             yield return new WaitForEndOfFrame();    
    16.         }
    17.     }
    18.  
    19.     private void Update()
    20.     {
    21.         transform.Rotate(0, _currentSpeed, 0);
    22.     }
    23. }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Sure, that's reasonable, but then you're clamping it, so if it ever needs to move more than your clamp to maintain consistency, it won't.

    There's also an upper limit to how big Time.deltaTime will get... I think it is 3 or 5 frames worth of time, I forget. That can also introduce delay.
     
  3. PatD17th

    PatD17th

    Joined:
    Mar 27, 2013
    Posts:
    15
    I just fixed it, I had to put time.DeltaTime in this line
    Code (CSharp):
    1.  private void Update()
    2.     {
    3.         transform.Rotate(0, _currentSpeed * time.DeltaTime, 0);
    4.     }
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    That's a lot of code... have you considered just making an animation and being done with it?

    This is how I spin stuff when I don't do an animation:

    https://github.com/kurtdekker/makegeo/blob/master/makegeo/Assets/Scripts/SpinMeAllAxes.cs

    And even most of the above is quality of life boilerplate.

    At the end of the day it can just be an addition with Time.deltaTime and then set it into the object, like this:

    Code (csharp):
    1. void Update ()
    2. {
    3.   angle += RateOfSpin * Time.deltaTime;
    4.   transform.rotation = Quaternion.Euler (0, angle, 0);
    5. }
     
  5. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    720
    The rule of thumb here is to only include delta-time when actually changing something. So, you shouldn't multiple velocity by deltaTime before clamping it -- you aren't actually changing a value yet! You don't want the timestep to affect the actual velocity.

    Similarly, if you computing acceleration, you should multiply by deltaTime when you're adding to the velocity -- not before.
     
  6. PatD17th

    PatD17th

    Joined:
    Mar 27, 2013
    Posts:
    15
    So how should I fix this?

    Should I replace

    Code (CSharp):
    1.  private IEnumerator Start()
    2.     {
    3.         var currentTime = 0f;  
    4.         while (_currentSpeed < _maxSpeed)
    5.         {
    6.             currentTime += Time.deltaTime;
    7.             _currentSpeed = Mathf.Clamp(_rotationSpeed * currentTime, _minSpeed, _maxSpeed);  //"_currentSpeed" = clamped value of rotationSpeed with min max values.
    8.             yield return new WaitForEndOfFrame();  
    9.         }
    10.     }
    With:

    Code (CSharp):
    1.  private IEnumerator Start()
    2.     {  
    3.         while (_currentSpeed < _maxSpeed)
    4.         {
    5.            _currentSpeed = Mathf.Clamp(_rotationSpeed * time.DeltaTime, _minSpeed, _maxSpeed);  //"_currentSpeed" = clamped value of rotationSpeed with min max values.
    6.             yield return new WaitForEndOfFrame();  
    7.         }
    8.     }
     
    Last edited: Jan 31, 2023
  7. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    720
    If you want to accelerate from _minSpeed to _maxSpeed, then it should look something like this:

    Code (CSharp):
    1. while (speed < maxSpeed) {
    2.   speed += acceleration * Time.deltaTime;
    3.   speed = Mathf.Clamp(speed, minSpeed, maxSpeed);
    4.   yield return null;
    5. }
    Your first example is almost identical. I just renamed "rotation speed" to "acceleration". If a value decides how quickly a speed changes, then that value is an acceleration.