将 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.Lerp
将 GameObject 从位置 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;
}
}
我想用 Vector3.MoveTowards
within x seconds and in a coroutine function. I know how to do this with Vector3.Lerp
将 GameObject 从位置 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
totoPosition
with each frame moving certain distancetime
.
因此使用 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;
}
}