我想用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的答案解决了这两个问题。
答案 0 :(得分:5)
由于我很长时间没有接触Unity ...,但我确实相信您会弄乱计算。
首先,Vector3.MoveTowards(currentPos, toPosition, time)
在谈论
每帧移动时从
currentPos
到toPosition
步行 一定距离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;
}
}