Удалить задержку между lerps

Я сделал простой сценарий, который идет к одной путевой точке, а затем к следующей.

Моя проблема в том, что, кажется, задержка при переходе от waypoint1 к waypoint2, и я не знаю почему: https://s tackru.com/images/b38b67b4bee645e93727f68792c48cc5b83cbecc.gif

¿Почему происходит задержка и как я могу ее устранить?

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

3 ответа

Решение

Это происходит, потому что вы используете 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 - 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. Уравнение Лерпа для этого будет

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

Надеюсь это поможет. Мне жаль, что я не смог правильно отформатировать свой ответ, надеюсь, мне будет легче ответить. Любые правки для улучшения ответа приветствуются:)

Я рекомендую использовать 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

Другие вопросы по тегам