首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Mathf.SmoothDamp在协程中花费的时间比预期的要长

Mathf.SmoothDamp在协程中花费的时间比预期的要长
EN

Stack Overflow用户
提问于 2021-11-13 13:30:14
回答 2查看 187关注 0票数 1

我正在尝试移动和旋转协程中的游戏对象,以平滑地到达目标位置。为此,我尝试使用Mathf.SmoothDamp()计算因子,我在lerping函数中使用该因子。这是我的方法:

代码语言:javascript
运行
复制
    private IEnumerator ReachTarget()
    {
        _speed = 0f;
        var lerpFactor = 0f;
        var startingPosition = transform.position;
        var startingRotation = transform.rotation;

        while (lerpFactor < 0.99f)
        {
            lerpFactor = Mathf.SmoothDamp(lerpFactor, 1f, ref _speed, 1f);

            transform.position = Vector3.Lerp(startingPosition, _targetTransform.position, lerpFactor);
            transform.rotation = Quaternion.Lerp(startingRotation, _targetTransform.rotation, lerpFactor);

            yield return null;
        }

        transform.position = _targetTransform.position;
        transform.rotation = _targetTransform.rotation;
    }

根据Mathf.SmoothDamp()的文档,它应该在一秒内将我的lerpFactor0更改为1,这反过来应该在一秒内将我的对象移动和旋转到它的目标位置。然而,这根本不会发生,而且lerpFactor需要更长的时间(大约3秒)才能到达1 (我使用0.99是因为它永远不会真正到达1,只是非常接近)。

我认为这可能是因为Mathf.SmoothDamp()默认使用Time.deltaTime,这可能在协程中不起作用。因此,我尝试提供自己的值:

代码语言:javascript
运行
复制
    private IEnumerator ReachTarget()
    {
        _speed = 0f;
        var lerpFactor = 0f;
        var startingPosition = transform.position;
        var startingRotation = transform.rotation;
        var prevTime = Time.realtimeSinceStartup;

        while (lerpFactor < 0.99f)
        {
            var time = Time.realtimeSinceStartup - prevTime;
            prevTime = Time.realtimeSinceStartup;

            lerpFactor = Mathf.SmoothDamp(lerpFactor, 1f, ref _speed, 1f, maxSpeed: 1000f, time); // using 1000f for max speed

            transform.position = Vector3.Lerp(startingPosition, _targetTransform.position, lerpFactor);
            transform.rotation = Quaternion.Lerp(startingRotation, _targetTransform.rotation, lerpFactor);

            yield return null;
        }

        transform.position = _targetTransform.position;
        transform.rotation = _targetTransform.rotation;
    }

这并没有改变任何事情,lerpFactor到达1也需要同样的时间。

我怎么才能让它像它应该的那样工作呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-11-15 21:11:18

SmoothDamp的smoothTime只是一个近似值,不会很精确,因为更多的努力是为了不超过目标。

我建议你切换到SmoothStep或动画曲线,在那里你可以根据自己的喜好自定义插值(例如,添加过冲和反弹效果)。

下面是一个smoothTime更加精确的例子

代码语言:javascript
运行
复制
using System.Collections;
using UnityEngine;

public class LerpTest : MonoBehaviour
{
    [SerializeField] private Transform _targetTransform;
    [SerializeField] private AnimationCurve _animationCurve;
    private Vector3 startingPosition;
    private Quaternion startingRotation;

    void Start()
    {
        startingPosition = transform.position;
        startingRotation = transform.rotation;
    }

    private void Update()
    {
        if (Input.anyKeyDown)
        {
            StopAllCoroutines();
            transform.position = startingPosition;
            transform.rotation = startingRotation;
            StartCoroutine(ReachTarget(1f));
        }
    }

    private IEnumerator ReachTarget(float smoothTime)
    {
        var elapsedTime = 0f;

        while (elapsedTime < smoothTime)
        {
            float lerpFactor = Mathf.SmoothStep(0f, 1f, elapsedTime / smoothTime);
            // Or use an animation curve to customize the smoothing curve:
            // float lerpFactor = _animationCurve.Evaluate(elapsedTime / smoothTime);
            
            elapsedTime += Time.deltaTime;
            
            transform.position = Vector3.Lerp(startingPosition, _targetTransform.position, lerpFactor);
            transform.rotation = Quaternion.Slerp(startingRotation, _targetTransform.rotation, lerpFactor);

            yield return null;
        }

        Debug.Log($"Elapsed time: {elapsedTime} seconds");

        transform.position = _targetTransform.position;
        transform.rotation = _targetTransform.rotation;
    }
}

顺便说一句,我建议您使用Quaternion.Slerp而不是lerp来获得更好的插值效果,并且可以在corountines中随意使用Time.deltaTime -它工作得很好。

票数 1
EN

Stack Overflow用户

发布于 2021-11-15 14:22:55

你不必使用平滑阻尼来计算lerpFactor。Lerp因子就是经过的时间和持续时间的比率。所以如果你想在一秒钟内完成你的动画;

代码语言:javascript
运行
复制
private IEnumerator ReachTarget()
{
    float timeElapsed = 0;
    float lerpDuration = 1f;
    float lerpFactor;
    while (timeElapsed < lerpDuration)
    {
        lerpFactor = timeElapsed / lerpDuration;
        // Use lerpFactor in your lerp functions
        timeElapsed += Time.deltaTime;
        yield return null;
    }
}
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69954720

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档