【问题标题】:How do I add easing to a scripted transform animation in Unity?如何在 Unity 中为脚本化变换动画添加缓动?
【发布时间】:2020-11-02 21:56:01
【问题描述】:

我现在有一个设置,其中我有一个 3D 对象,该对象内部有一个空对象作为其父对象。当您按下一个按钮时,相机跟随的空物体会旋转 90 度。如果您按下另一个按钮,它将向另一个方向旋转 90 度。其结果是,相机可以在完成旋转之前围绕对象旋转 4 次。

目前它运行良好,但我正试图弄清楚如何为动画添加一些缓动,使其看起来不那么粗糙。我对在动画中使用曲线有一点了解,但我不确定如何将其应用到代码中(或者它是否是最好的处理方式)

    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");
    }


上面的代码是我创建协程的地方,它说明了它将如何转换。在这里让我有点困惑的一件事是,如果我没有写着 transform.rotation = toangle; 的行,旋转就会出现在 89.5 度左右,如果你多次这样做,它会偏离几度。不知道为什么会这样。

    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));
        }
    }

这部分是动画被调用的地方。非常感谢任何帮助。

【问题讨论】:

  • 你会想要一个AnimationCurve ;) 或者,查看一个补间包。我推荐“DOTween”。
  • 欢迎新用户,您绝对想为此使用 Unity 的“动画”系统。花 5 分钟使用它就非常简单。

标签: c# unity3d


【解决方案1】:

看看Animation Curves 就像@immersive 说的那样。

您可以轻松定义自己的curves in inspector 只需将其添加到您的代码中:

public AnimationCurve curve;

然后您可以使用AnimationCurve.Evaluate 对曲线进行采样。

另一种方法是使用 AssetStore/Package Manager 中的预制库,例如 DOTween 或 LeanTween。

【讨论】:

  • 他们有多好!?!我厌倦了不得不用 LeanTween/DOTween 编写自定义补间,然后我发现了 AnimationCurve 并且我的一半代码消失了!使用简单,但功能强大!
  • 您只是必须使用 Unity中的Animator。永远不要编写补间代码。您不妨坐下来编写自己的物理代码。
【解决方案2】:

内嵌评论:

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;
    }

}

【讨论】:

    【解决方案3】:
    for (var t = 0f; t < 1; t += Time.deltaTime / intime)
    {
        transform.rotation = Quaternion.Slerp(fromangle, toangle, t);
        yield return null;
    }
    transform.rotation = toangle;
    

    因为t 不等于 1。

    你只需要在循环之后设置旋转到目标。

    【讨论】:

    • 不过,这只是一个线性缓解 lerp,对吧?它不处理像慢-快-慢(又名,缓进-出)lerps 之类的事情?
    • 顺便说一句 @Immersive 如果你真的想调整自己,我真的建议不要打扰所谓的包。只需使用 tweeng 扩展,它是一行代码 stackoverflow.com/a/37228628/294884 就像您在下面所说的那样,但对于这样的每种情况,必须使用 Unity 的 Animator
    • @Fattie 你的吐温很酷!这些包主要是为了方便他们预先制作的钩子/动作。 (而不是将新手扔到扩展和操作的深处=)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多