【问题标题】:Remove delay between lerps消除 lerps 之间的延迟
【发布时间】:2018-12-24 18:45:13
【问题描述】:

我制作了一个简单的脚本,它先到一个航点,然后再到下一个。

我的问题是从航点 1 到航点 2 似乎有延迟,我不知道为什么:

¿为什么会发生这种延迟,我该如何消除它?

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);
 }
 }

【问题讨论】:

    标签: unity3d lerp


    【解决方案1】:

    发生这种情况,因为您使用的 lerp 并不完全正确。如果你想获得线性运动,你应该缓存你的第一个参数(开始时的位置/旋转)并提供增加的第三个参数。发生这种延迟是因为如果您的子弹非常接近最终位置并且它仍在尝试到达那里,但是您当前的距离 |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 来控制移动持续时间。

    【讨论】:

    • 如果我想提高 lerp 速度,我应该在第三个参数上添加一个乘数?
    • 确实如此,但请记住,如果 finalPos 和 startPos 之间的距离会改变您的速度,则取决于此距离。因此,如果您的距离是 1 米或 10 米,那么它会同时行进这个距离。如果你不想要这个,你应该提供速度变量并将你的 T 除以(距离/速度)。
    • 所以应该是: Vector3.Lerp(startPos, finalPos, currentT / ( Vector3.Distance(startPos, finalPos) / speed)); ?
    • 是的,类似的。请注意,您不需要在每一帧中计算距离,而只需每次行程计算一次。
    • 很抱歉一直打扰它,但添加速度公式让我回到最初的问题:imgur.com/a/nqQ5pbc
    【解决方案2】:

    所以首先阅读这些帖子以更好地理解 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 返回的值是它们之间的 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);
    

    希望这会有所帮助。很抱歉我无法正确格式化我的答案,希望能更好地回答。欢迎进行任何修改以改进答案:)

    【讨论】:

      【解决方案3】:

      我建议使用 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多