我正在尝试移动和旋转协程中的游戏对象,以平滑地到达目标位置。为此,我尝试使用Mathf.SmoothDamp()
计算因子,我在lerping函数中使用该因子。这是我的方法:
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()的文档,它应该在一秒内将我的lerpFactor
从0
更改为1
,这反过来应该在一秒内将我的对象移动和旋转到它的目标位置。然而,这根本不会发生,而且lerpFactor
需要更长的时间(大约3秒)才能到达1
(我使用0.99
是因为它永远不会真正到达1
,只是非常接近)。
我认为这可能是因为Mathf.SmoothDamp()
默认使用Time.deltaTime
,这可能在协程中不起作用。因此,我尝试提供自己的值:
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
也需要同样的时间。
我怎么才能让它像它应该的那样工作呢?
发布于 2021-11-15 21:11:18
SmoothDamp的smoothTime只是一个近似值,不会很精确,因为更多的努力是为了不超过目标。
我建议你切换到SmoothStep或动画曲线,在那里你可以根据自己的喜好自定义插值(例如,添加过冲和反弹效果)。
下面是一个smoothTime更加精确的例子
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 -它工作得很好。
发布于 2021-11-15 14:22:55
你不必使用平滑阻尼来计算lerpFactor。Lerp因子就是经过的时间和持续时间的比率。所以如果你想在一秒钟内完成你的动画;
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;
}
}
https://stackoverflow.com/questions/69954720
复制相似问题