结合使用MoveTowards和持续时间而不是速度

时间:2018-07-04 03:17:59

标签: c# unity3d lerp

我想用Vector3.MoveTowards在x秒内并在协同程序中将 GameObject 从位置A移到位置B。我知道如何使用Vector3.Lerp来执行此操作,但是这次最好使用Vector3.MoveTowards来执行此操作,因为两个函数的行为都不同。

使用Vector3.Lerp可以像this一样完成

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内在协程函数中用https://codepen.io/mcanterel/pen/LroRYz将GameObject从位置A移到位置B?

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

编辑

替换

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

使用

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

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

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

1 个答案:

答案 0 :(得分:5)

由于我很长时间没有接触Unity ...,但我确实相信您会弄乱计算。

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

  

每帧移动时从currentPostoPosition步行   一定距离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)/持续时间,全速的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;
    }
}