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. Dismiss Notice

Bug Weird behavior, rotation speeds up

Discussion in 'Scripting' started by Salazans, Feb 18, 2022.

  1. Salazans

    Salazans

    Joined:
    Feb 9, 2022
    Posts:
    5
    Hi everyone,

    I'm making this "laser aim" effect that follows the player, but it seems to "snap" to the player and disregard the maximum rotate speed. I don't know what's going on here:

    Desktop 2022.02.18 - 20.14.38.02.DVR.gif

    Here code:

    Code (CSharp):
    1. // This happens on LateUpdate
    2. transform.rotation = Quaternion.RotateTowards(transform.rotation, GetFollowPlayerRotation(), turnSpeed * Time.deltaTime);
    3.  
    4. private Quaternion GetFollowPlayerRotation()
    5. {
    6.     float angle = Vector3.SignedAngle(Vector3.down, (followTarget.position - transform.position).normalized, Vector3.forward);
    7.     Quaternion rotationToTarget = Quaternion.Euler(0, 0, angle);
    8.     return rotationToTarget;
    9. }
    10.  
     
  2. coder091

    coder091

    Joined:
    Feb 16, 2021
    Posts:
    23
    when transform of the player gets close to the beam, your math seems to broke down,
    here is what would I do,

    - i would debug.log the "angle" variable to see whats going on in there.
    - after i collect enough information about the variable, i come to a conclusion about why it acts that why,
    - then i fix my code accordingly.
     
  3. Salazans

    Salazans

    Joined:
    Feb 9, 2022
    Posts:
    5
    Hi, thanks for replying

    Debugging the angle itself didn't help, but it led me on a path, and I think I've determined that the Quaternion.RotateTowards function is bugged.
    Testing showed that, for tiny angle differences (about 0.16 degrees or less), RotateTowards ignores the maxDegreesDelta parameter and rotates the full angle difference.

    Here's my debugging code:

    Code (CSharp):
    1. turnSpeed = 5;
    2. Quaternion followRotation = GetFollowPlayerRotation();
    3. rotation = Quaternion.RotateTowards(transform.rotation, followRotation, turnSpeed * Time.deltaTime);
    4.  
    5. Debug.Log("actual turn speed: " + (rotation.eulerAngles.z - transform.rotation.eulerAngles.z) / Time.deltaTime +
    6.     "\n\ntransform angle: " + transform.rotation.eulerAngles.z +
    7.     "\nfollow angle: " + followRotation.eulerAngles.z +
    8.     "\n\ndifference: " + Mathf.Abs(transform.rotation.eulerAngles.z - followRotation.eulerAngles.z) +
    9.     "\nturnSpeed * dTime: " + turnSpeed * Time.deltaTime +
    10.     "\n\nexpected change: " + Mathf.Min(Mathf.Abs(followRotation.eulerAngles.z - transform.rotation.eulerAngles.z), turnSpeed * Time.deltaTime) +
    11.     "\nactual change: " + Mathf.Abs(rotation.eulerAngles.z - transform.eulerAngles.z) +
    12.     "\n");
    13.  
    Here's the output of a correct rotation when the player is far from the beam:

    upload_2022-2-19_13-36-59.png

    And here's the output of a "snapped" rotation. Notice how the function returned exactly the angle difference, which is bigger than maxDegreesDelta:

    upload_2022-2-19_13-38-46.png

    I suppose I should file a bug report and perform the rotation manually.
     
  4. alexeu

    alexeu

    Joined:
    Jan 24, 2016
    Posts:
    257
    Are you in 2D or 3D ?
     
  5. Salazans

    Salazans

    Joined:
    Feb 9, 2022
    Posts:
    5
    So I ditched Quaternion.RotateTowards and went with the following code, which works great:

    Edit: nope, I failed to account for the change from 360° to 0°. Will update code
     
    Last edited: Feb 19, 2022
  6. Salazans

    Salazans

    Joined:
    Feb 9, 2022
    Posts:
    5
    Okay so here's the code that actually works:

    Code (CSharp):
    1. // rotation = Quaternion.RotateTowards(transform.rotation, GetFollowPlayerRotation(), turnSpeed * Time.deltaTime);
    2.  
    3. float angleBetween = GetFollowPlayerRotation().eulerAngles.z - transform.rotation.eulerAngles.z;
    4. if (angleBetween < -180) angleBetween += 360;
    5. else if (angleBetween > 180) angleBetween -= 360;
    6.  
    7. float maxTurn = turnSpeed * Time.deltaTime;
    8. float actualTurn = Mathf.Clamp(angleBetween, -maxTurn, maxTurn);
    9. rotation = transform.rotation * Quaternion.Euler(0, 0, actualTurn);
    10.  
     
  7. Salazans

    Salazans

    Joined:
    Feb 9, 2022
    Posts:
    5
    Hi there, this project is in 2d