Home > front end >  How can I smooth rotation which is based on cursor position?
How can I smooth rotation which is based on cursor position?

Time:11-18

private float rotationZ;

        Vector3 difference = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
    difference.Normalize();
    


    float rotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;

    transform.rotation = Quaternion.Euler(0f, 0f, rotationZ);

So far my code will get the cursor position and instantly perform a transform. However, if I move the cursor near the center of the pivot, the rotation will be instantaneous and choppy. How can I add a slight smooth to this, to make it travel from point A to point B slower?

CodePudding user response:

You're looking for Mathf.Lerp

Example of how you could use it:

    float rotationZ;

    //Changes how quickly will rotate 
    const float rotationSpeed = 0.58f;

    Vector3 difference = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
    difference.Normalize();

    rotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;

    float lerpRotation = Mathf.Lerp(transform.rotation.z, rotationZ, Time.deltaTime * rotationSpeed);
    transform.rotation = Quaternion.Euler(0f, 0f, lerpRotation);

CodePudding user response:

You would store the actual target value in a field and then move towards it

private Quaternion targetRotation;
private Camera camera;

private void Awake ()
{
    // Camera.main is quite expensive so rather store the reference
    camera = Camera.main;
  
    // Initially set your current rotation as target
    // especially important if you don't always update the target rotation but e.g.
    // only if a certain button is pressed  
    targetRotation = transform.rotation;
}

private void Update ()
{
    UpdateTargetRotation();
    RotateTowardsTarget();
}

private void UpdateTargetRotation ()
{
    var difference = (camera.ScreenToWorldPoint(Input.mousePosition) - transform.position).normalized;
    var targetRotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;

    targetRotation = Quaternion.Euler(0, 0, targetRotationZ);
}

Now for the RotateTowardsTarget you have many options.

One of them would indeed be using Quaternion.Lerp with a certain interpolation factor. Here you interpolate smoothly towards the target value but very fast at the beginning and get slower and slower the closer you get to the target value regardless of how much you rotate in total. This also might never really reach the exact target value.

// Adjust in the Inspector
public float interpolationFactor = 5f;

private void RotateTowardsTarget ()
{
    transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, interpolationFactor * Time.deltaTime);
}

Or another option would be to rather use Quaternion.RotateTowards which rotates with a fixed speed

// Adjust in the Inspector
public float anglePerSecond = 45;

private void RotateTowardsTarget ()
{
    transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, anglePerSecond * Time.deltaTime);
}

CodePudding user response:

You should use Quaternion.Slerp() in a coroutine. You check the cursor position every FixedUpdate then start a coroutine that interpolates and sets the rotation every frame until the next FixedUpdate comes. The created lag is basicly unnoticable and it looks silky smooth.

For the interpolation t value you should use a variable that stores the time elapsed since the last FixedUpdate (you add that up from time.deltatimes), and to get the t you just divide it by 0.02secs.

Then when the coroutin finishes, set the rotation to the final value.

  • Related