0

I've got a setup right now where I have a 3D object with an empty object parented to it inside the object. When you press one button, an empty object that the camera is following rotates 90 degrees. If you press the other button, it rotates the other direction in 90 degrees. The result is that the camera can spin around the object 4 times before it makes a complete rotation.

Currently it works well, but I'm trying to figure out how I add some easing to the animation so it doesn't look so rough. I know a little about working with curves in animation but I'm not sure how I can apply that to code (or if it's even the best way to do things)

    public InputMaster controls;
    private bool isSpinning;
    private float rotationSpeed = 0.3f;

    IEnumerator RotateMe(Vector3 byangles, float intime)
    {
        var fromangle = transform.rotation;
        var toangle = Quaternion.Euler(transform.eulerAngles + byangles);
        for (var t = 0f; t < 1; t += Time.deltaTime / intime)
        {
            transform.rotation = Quaternion.Slerp(fromangle, toangle, t);
            yield return null;
            transform.rotation = toangle;
        }

            Debug.Log("finished rotation");
            isSpinning = false;
            Debug.Log("isSpinning now false");
    }


code above is where I create a coroutine that says how it is going to transform. One thing that confuses me here a little is that if I don't have the line that says transform.rotation = toangle; , the rotation comes out at like 89.5 degrees or something, and if you do it multiple times it goes several degrees off. Not sure why that happens.

    void Rotation(float amount)
    {
        Debug.Log("rotation number is " + amount);

        float holdingRotate = controls.Player.Camera.ReadValue<float>();

        if (holdingRotate == 1 && isSpinning == false)
        {
            isSpinning = true;
            Debug.Log("isSpinning now true");
            StartCoroutine(RotateMe(Vector3.up * 90, rotationSpeed));

        }
        else if (holdingRotate == -1 && isSpinning == false)
        {
            isSpinning = true;
            Debug.Log("isSpinning now true");
            StartCoroutine(RotateMe(Vector3.up * -90, rotationSpeed));
        }
    }

and this part is where the animation gets called up. Any help much appreciated.

mikaelm
  • 51
  • 6
  • 1
    You'll want an ```AnimationCurve``` ;) Alternatively, look into a tweening package. I recommend "DOTween". – Immersive Nov 02 '20 at 10:20
  • Welcome new user, you ABSOLUTELY want to use Unity's "Animation" system for this. It is incredibly easy once you spend 5 minutes using it. – Fattie Nov 02 '20 at 13:59

3 Answers3

3

Have a look at Animation Curves like @immersive said.

You can easily define your own curves in inspector simply by adding this to your code:

public AnimationCurve curve;

Curve in Inspector

You can then use AnimationCurve.Evaluate to sample the curve.

The alternative is to use a premade library from the AssetStore/Package Manager like DOTween or LeanTween to name some.

KYL3R
  • 3,877
  • 1
  • 12
  • 26
  • How good are they!?! I got so sick of having to write custom tweeners with LeanTween/DOTween, and then I found out about ```AnimationCurve``` and half my code disappeared! Simple to use, but so powerful! – Immersive Nov 02 '20 at 13:59
  • You simply **must use** Animator in Unity. Never write tween code. You might as well sit down and write your own physics code. – Fattie Nov 02 '20 at 14:02
1

Comments inline:

public class SmoothRotator : MonoBehaviour
{

    // Animation curve holds the 'lerp factor' from starting angle to final angle over time
    // (Y axis is blend factor, X axis is normalized 'time' factor)
    public AnimationCurve Ease = AnimationCurve.EaseInOut(0, 0, 1, 1);
    public float Duration = 1f;

    private IEnumerator ActiveCoroutine = null;

    public void RotateToward(Quaternion targetAngle) {

        // If there's a Coroutine to stop, stop it.
        if (ActiveCoroutine != null)
            StopCoroutine(ActiveCoroutine);

        // Start new Coroutine and cache the IEnumerator in case we need to interrupt it.
        StartCoroutine(ActiveCoroutine = Rotator(targetAngle));
    }

    public IEnumerator Rotator(Quaternion targetAngle) {

        // Store starting angle
        var fromAngle = transform.rotation;

        // Accumulator for Time.deltaTime
        var age = 0f; 

        while (age < 1f) {
            // normalize time (scale to "percentage complete") and clamp it
            var normalisedTime = Mathf.Clamp01(age / Duration);

            // Pull lerp factor from AnimationCurve
            var lerpFactor = Ease.Evaluate(normalisedTime);

            // Set rotation
            transform.rotation = Quaternion.Slerp(fromAngle, targetAngle, lerpFactor);

            // Wait for next frame
            yield return null;
            // Update age with new frame's deltaTime
            age += Time.deltaTime;
        }

        // Animation complete, force true value
        transform.rotation = targetAngle;

        // Housekeeping, clear ActiveCoroutine
        ActiveCoroutine = null;
    }

}
Immersive
  • 1,684
  • 1
  • 11
  • 9
0
for (var t = 0f; t < 1; t += Time.deltaTime / intime)
{
    transform.rotation = Quaternion.Slerp(fromangle, toangle, t);
    yield return null;
}
transform.rotation = toangle;

Because t won't equal to 1.

You just need to set the rotation to the target after the loop.

shingo
  • 18,436
  • 5
  • 23
  • 42
  • That's just a linear-ease lerp, though, right? It doesn't handle things like slow-fast-slow (aka, ease-in-out) lerps? – Immersive Nov 02 '20 at 10:24
  • Just BTW @Immersive I would truly recommend to never bother with so-called packages if you really want to tweeng yourself. Just use a tweeng extension which is a line of code https://stackoverflow.com/a/37228628/294884 Exactly as you say below though one **MUST USE** Unity's Animator for every case like this – Fattie Nov 02 '20 at 14:04
  • @Fattie Your Tweeng is pretty cool! The packages are mostly for convenience with their pre-made hooks/actions. (And not throwing newbies into the deep end of extensions and Actions =) – Immersive Nov 02 '20 at 14:10