消除 lerps 之间的延迟
Remove delay between lerps
我制作了一个简单的脚本,可以转到一个航路点然后到下一个航路点。
我的问题是从 waypoint1 到 waypoint2 似乎有延迟,我不知道为什么:
¿为什么会发生这种延迟,我该如何消除它?
using UnityEngine;
using System.Collections;
public class Missile : MonoBehaviour
{
public Vector3 finalTarget;
public Transform forwardObject;
public GameObject impactAreaPrefab;
float smoothingDelay = 0.1f;
bool fired = false;
bool powerPhase = true;
Vector3 currentTarget;
private void OnEnable() {
fire(new Vector3(-25.29f, 0.5f, -10.638f));
}
void fire(Vector3 coords) {
currentTarget = forwardObject.position;
finalTarget = coords;
Instantiate(impactAreaPrefab, finalTarget, Quaternion.identity);
fired = true;
}
void Update() {
if (!fired) {
return;
}
if (powerPhase && transform.position == currentTarget) {
powerPhase = false;
currentTarget = finalTarget;
smoothingDelay = 0.05f;
}
transform.position = Vector3.Lerp(transform.position, currentTarget, Time.deltaTime / smoothingDelay);
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, currentTarget, 1, 0.0f)), Time.deltaTime / smoothingDelay);
}
}
这种情况正在发生,因为您没有完全正确地使用 lerp。如果你想获得线性运动,你应该缓存你的第一个参数(开始时 position/rotation )并提供增加的第三个参数。发生这种延迟是因为如果你的子弹非常接近最终位置并且它仍在尝试到达那里,但你当前的距离 |finalPos - transform.position|太小了,你的步Time.deltaTime/smoothingDelay几乎不动了。
Vector3 startPos;
Vector3 finalPos;
float currentT = 0.0f;
void Update()
{
currentT += Time.deltaTime;
transform.position = Vector3.Lerp(startPos, finalPos, currentT);
}
检查是否 Vector3 == Vector3 也不是一个好主意。使用上面的模式并检查 currentT 是否大于或等于 1。如果为真,那么您处于最终位置。您还可以通过除以 currentT 来控制移动持续时间。
我建议使用 iTween 以实现流畅的移动。
我在某个时候修改了 iTween,以便能够做任何我想做的事情。像这样:
public static void Rotate (Transform transform, Vector3 target, float transitionTime, Action onEnd = null, bool ignoreTimescale = false, iTween.EaseType ease = iTween.EaseType.easeInOutQuad, float delay = 0)
{
Vector3 from, to;
from = transform.localEulerAngles;
to = target;
Action <object> onUpdateAction = (rotation =>
{
transform.localEulerAngles = (Vector3) rotation;
});
Action <object> onCompleteAction = (data =>
{
if (onEnd != null)
onEnd ();
});
Hashtable hash = new Hashtable ();
hash.Add ("from", from);
hash.Add ("to", to);
hash.Add ("time", transitionTime);
hash.Add ("delay", delay);
hash.Add ("easetype", iTween.EaseType.easeInOutQuad);
hash.Add ("ignoretimescale", ignoreTimescale);
hash.Add ("onupdate", onUpdateAction);
hash.Add ("oncomplete", onCompleteAction);
iTween.ValueTo (transform.gameObject, hash);
}
这让我可以在各种情况下完全控制。
如果你想实现它,这里是代码。
https://drive.google.com/open?id=1nLEEYTp-q4Kfh2n3nWQJcMXmPNtVPLLP
所以首先阅读这些 post 以更好地理解 Lerp 函数-
https://chicounity3d.wordpress.com/2014/05/23/how-to-lerp-like-a-pro/
http://www.kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8
你现在应该对 lerp 有了更好的理解。
总之,lerp 做了一件非常简单的事情。假设你有两个值 X 和 Y。对于这个例子,让我们给它们一些值,X = 0,Y = 1,现在你想得到它们之间的某个百分比的值,比如你想得到一个 50% 的值从 X 和 Y。你可以猜到答案是 0.5。这个的 lerp 方程是
Mathf.Lerp(0, 1, 0.5f);
所以简单地-给定两个值,x 和 y,Mathf.Lerp returns 一个值在它们之间相差 t%。
现在要正确使用 Lerp,您需要在启动 lerp 之前缓存位置。大多数时候我使用协程来获得这种效果,然后你可以使用动画曲线来改变第三个参数来创造一些疯狂的好效果。例如关于使用动画曲线只是评论我会写它。
对于你的这个问题,你有两个选择-
1) 像专业人士一样使用动画曲线来操纵速度。请记住,您也可以在运行时创建动画曲线。
IENumerator Move(Transform toMove, Vector3 end, float duration){
Vector3 startPos = toMove.position;
float elapsed = 0f;
while(elapsed < duration){
elapsed += Time.deltaTime;
toMove.position = Vector3.Lerp(startPos, end, elapsed / duration);//manipulate the last parameter to move the object linearly
yield return null;//basically wait for next frame
}
toMove.position = end;//after lerp ends
}
现在您可以使用速度代替持续时间,然后用它计算所需的时间并更改速度以使其更快
float distance = Vector3.Distance(startPos, end);
toMove.position = Vector3.Lerp(startPos, end, elapsed / (distance/(speed * multiplier)));
2) 使用Vector3.MoveTowards - 此函数以给定的最大步长将点移动到终点,需要三个参数,(currentPosition, end, step),你可以将步长乘以变量来控制速度,两者都很好用。
在大多数情况下使用它要容易得多
示例-
float step = speed * Time.deltaTime;//to make it framerate independent
transform.position = Vector3.MoveTowards(transform.position, end, step * multiplier);
希望这对您有所帮助。很抱歉,我无法正确格式化我的答案,希望能更好地回答。欢迎任何改进答案的修改:)
我制作了一个简单的脚本,可以转到一个航路点然后到下一个航路点。
我的问题是从 waypoint1 到 waypoint2 似乎有延迟,我不知道为什么:
¿为什么会发生这种延迟,我该如何消除它?
using UnityEngine;
using System.Collections;
public class Missile : MonoBehaviour
{
public Vector3 finalTarget;
public Transform forwardObject;
public GameObject impactAreaPrefab;
float smoothingDelay = 0.1f;
bool fired = false;
bool powerPhase = true;
Vector3 currentTarget;
private void OnEnable() {
fire(new Vector3(-25.29f, 0.5f, -10.638f));
}
void fire(Vector3 coords) {
currentTarget = forwardObject.position;
finalTarget = coords;
Instantiate(impactAreaPrefab, finalTarget, Quaternion.identity);
fired = true;
}
void Update() {
if (!fired) {
return;
}
if (powerPhase && transform.position == currentTarget) {
powerPhase = false;
currentTarget = finalTarget;
smoothingDelay = 0.05f;
}
transform.position = Vector3.Lerp(transform.position, currentTarget, Time.deltaTime / smoothingDelay);
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, currentTarget, 1, 0.0f)), Time.deltaTime / smoothingDelay);
}
}
这种情况正在发生,因为您没有完全正确地使用 lerp。如果你想获得线性运动,你应该缓存你的第一个参数(开始时 position/rotation )并提供增加的第三个参数。发生这种延迟是因为如果你的子弹非常接近最终位置并且它仍在尝试到达那里,但你当前的距离 |finalPos - transform.position|太小了,你的步Time.deltaTime/smoothingDelay几乎不动了。
Vector3 startPos;
Vector3 finalPos;
float currentT = 0.0f;
void Update()
{
currentT += Time.deltaTime;
transform.position = Vector3.Lerp(startPos, finalPos, currentT);
}
检查是否 Vector3 == Vector3 也不是一个好主意。使用上面的模式并检查 currentT 是否大于或等于 1。如果为真,那么您处于最终位置。您还可以通过除以 currentT 来控制移动持续时间。
我建议使用 iTween 以实现流畅的移动。
我在某个时候修改了 iTween,以便能够做任何我想做的事情。像这样:
public static void Rotate (Transform transform, Vector3 target, float transitionTime, Action onEnd = null, bool ignoreTimescale = false, iTween.EaseType ease = iTween.EaseType.easeInOutQuad, float delay = 0)
{
Vector3 from, to;
from = transform.localEulerAngles;
to = target;
Action <object> onUpdateAction = (rotation =>
{
transform.localEulerAngles = (Vector3) rotation;
});
Action <object> onCompleteAction = (data =>
{
if (onEnd != null)
onEnd ();
});
Hashtable hash = new Hashtable ();
hash.Add ("from", from);
hash.Add ("to", to);
hash.Add ("time", transitionTime);
hash.Add ("delay", delay);
hash.Add ("easetype", iTween.EaseType.easeInOutQuad);
hash.Add ("ignoretimescale", ignoreTimescale);
hash.Add ("onupdate", onUpdateAction);
hash.Add ("oncomplete", onCompleteAction);
iTween.ValueTo (transform.gameObject, hash);
}
这让我可以在各种情况下完全控制。
如果你想实现它,这里是代码。
https://drive.google.com/open?id=1nLEEYTp-q4Kfh2n3nWQJcMXmPNtVPLLP
所以首先阅读这些 post 以更好地理解 Lerp 函数- https://chicounity3d.wordpress.com/2014/05/23/how-to-lerp-like-a-pro/ http://www.kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8
你现在应该对 lerp 有了更好的理解。 总之,lerp 做了一件非常简单的事情。假设你有两个值 X 和 Y。对于这个例子,让我们给它们一些值,X = 0,Y = 1,现在你想得到它们之间的某个百分比的值,比如你想得到一个 50% 的值从 X 和 Y。你可以猜到答案是 0.5。这个的 lerp 方程是
Mathf.Lerp(0, 1, 0.5f);
所以简单地-给定两个值,x 和 y,Mathf.Lerp returns 一个值在它们之间相差 t%。
现在要正确使用 Lerp,您需要在启动 lerp 之前缓存位置。大多数时候我使用协程来获得这种效果,然后你可以使用动画曲线来改变第三个参数来创造一些疯狂的好效果。例如关于使用动画曲线只是评论我会写它。
对于你的这个问题,你有两个选择-
1) 像专业人士一样使用动画曲线来操纵速度。请记住,您也可以在运行时创建动画曲线。
IENumerator Move(Transform toMove, Vector3 end, float duration){
Vector3 startPos = toMove.position;
float elapsed = 0f;
while(elapsed < duration){
elapsed += Time.deltaTime;
toMove.position = Vector3.Lerp(startPos, end, elapsed / duration);//manipulate the last parameter to move the object linearly
yield return null;//basically wait for next frame
}
toMove.position = end;//after lerp ends
}
现在您可以使用速度代替持续时间,然后用它计算所需的时间并更改速度以使其更快
float distance = Vector3.Distance(startPos, end);
toMove.position = Vector3.Lerp(startPos, end, elapsed / (distance/(speed * multiplier)));
2) 使用Vector3.MoveTowards - 此函数以给定的最大步长将点移动到终点,需要三个参数,(currentPosition, end, step),你可以将步长乘以变量来控制速度,两者都很好用。 在大多数情况下使用它要容易得多 示例-
float step = speed * Time.deltaTime;//to make it framerate independent
transform.position = Vector3.MoveTowards(transform.position, end, step * multiplier);
希望这对您有所帮助。很抱歉,我无法正确格式化我的答案,希望能更好地回答。欢迎任何改进答案的修改:)