将 MoveTowards 与持续时间而不是速度一起使用

Use MoveTowards with duration instead of speed

我想用 Vector3.MoveTowards within x seconds and in a coroutine function. I know how to do this with Vector3.LerpGameObject 从位置 A 移动到 B 但这次我更愿意用 Vector3.MoveTowards 来做,因为两个函数的行为不同.

使用 Vector3.Lerp,这样做就像 :

IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
    float counter = 0;

    //Get the current position of the object to be moved
    Vector3 startPos = fromPosition.position;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
        yield return null;
    }
}

我尝试用 Vector3.MoveTowards 做同样的事情,但它不能正常工作。问题是移动在 x 时间或持续时间之前完成。而且,它的移动并不流畅。它跳到两个位置的中间而不是位置B的末尾。

这是使用 Vector3.MoveTowards 的函数,但存在上述问题:

IEnumerator MoveTowards(Transform objectToMove, Vector3 toPosition, float duration)
{
    float counter = 0;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        Vector3 currentPos = objectToMove.position;
        float time = Vector3.Distance(currentPos, toPosition) / duration;

        objectToMove.position = Vector3.MoveTowards(currentPos, toPosition,
         time);

        Debug.Log(counter + " / " + duration);
        yield return null;
    }
}

如何在协程函数中用 Vector3.MoveTowards 在 x 秒内将游戏对象从位置 A 移动到 B?

请不要推荐Vector3.Lerp,因为那不是我想用的。

编辑:

正在替换

float time = Vector3.Distance(currentPos, toPosition) / duration;

float time = Vector3.Distance(startPos, toPosition) / (duration * 60f);

有效,但当焦点从 Unity 转移到另一个应用程序时会出现问题。这样做会导致运动无法完成。在启动计时器之前每帧而不是一次计算它似乎更合理。

MatrixTai 的回答解决了这两个问题。

因为我已经很久没有接触 Unity 了……但我相信你在计算时搞砸了。

首先,Vector3.MoveTowards(currentPos, toPosition, time)说的是

Walking from currentPos to toPosition with each frame moving certain distance time.

因此使用 time 作为名称会造成混淆,但我们保留它。

但是,你会注意到在声明中,time是每帧移动的东西。但是 Vector3.Distance(currentPos, toPosition) / duration 是速度 (m/s),而不是 (m/frame)。要使其成为 (m/frame),只需乘以 Time.deltatime 即 (s/frame).

其次,

在协程中,这意味着该函数在每一帧中迭代。在行 float time = Vector3.Distance(currentPos, toPosition) / duration * Time.deltatime; 中,您会注意到随着距离越来越小,time 在进入下一帧时不断减小。

更具体地说,我们可以做一些数学运算。通常这应该用微积分来完成,但让我们通过仅考虑 2 点来简化它。当物体位置 d = 0 且物体位置 d ~= 9.9 时,假设端点为 10。

在点 1,对象有 time = (10-0)/持续时间,全速。 在点 2,对象具有 time = (10-9.9)/duration,全速的 1/10。

除非你想让它每帧移动得慢一点,否则你不能保持duration的值不变。由于在每一帧之后,您希望保持速度,因此持续时间应随距离减少。

要使该物理起作用,减去经过的时间的持续时间。

所以最终的解决方案是

float time = Vector3.Distance(currentPos, toPosition) / (duration-counter) * Time.deltaTime;

完整函数如下:

IEnumerator MoveTowards(Transform objectToMove, Vector3 toPosition, float duration)
{
    float counter = 0;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        Vector3 currentPos = objectToMove.position;

        float time = Vector3.Distance(currentPos, toPosition) / (duration - counter) * Time.deltaTime;

        objectToMove.position = Vector3.MoveTowards(currentPos, toPosition, time);

        Debug.Log(counter + " / " + duration);
        yield return null;
    }
}