4

我想在 x 秒内和协程函数中将GameObject从位置 A 移动到 B。Vector3.MoveTowards我知道如何做到这一点,Vector3.Lerp但这次更愿意这样做,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 秒内并在协程函数中将 GameObject 从位置 A 移动到 B?

请不要建议Vector3.Lerp,因为那不是我想要使用的。

编辑

更换

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

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

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

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

4

1 回答 1

7

因为我很长时间没有接触 Unity ......但我相信你在计算中搞砸了。

首先,Vector3.MoveTowards(currentPos, toPosition, time)是在谈论

currentPostoPosition每帧移动一定的距离time

因此使用timeas name 会令人困惑,但可以保留它。

但是,你会注意到在声明中,time是每帧移动的东西。但是Vector3.Distance(currentPos, toPosition) / duration是速度(米/秒),而不是(米/帧)。要做到(米/帧),只需乘以Time.deltatime(秒/帧)。

第二,

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

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

在点 1,对象有time= (10-0)/duration,全速。在点 2,物体有time= (10-9.9)/duration,全速的 1/10。

除非您希望它每帧移动得更慢,否则您不能保持持续时间的值不变。在每一帧之后,您希望保持速度,因此持续时间应该随着距离而减少。

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

所以最终的解决方案是

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;
    }
}
于 2018-07-04T04:58:10.367 回答