Удалить задержку между 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