我制作了一个简单的脚本,该脚本先到达一个路标,然后到达下一个路标。
我的问题是从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);
}
}
答案 0 :(得分: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。如果为true,则您处于最终位置。通过除以currentT,您还可以控制运动持续时间。
答案 1 :(得分:1)
因此,首先阅读这些文章以更好地了解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),您可以将step与变量相乘以控制速度,两者均有效真的很好 在大多数情况下,使用它会容易得多 示例-
float step = speed * Time.deltaTime;//to make it framerate independent
transform.position = Vector3.MoveTowards(transform.position, end, step * multiplier);
希望这会有所帮助。抱歉,我无法正确设置答案的格式,希望答案会更好。欢迎进行任何改进答案的修改:)
答案 2 :(得分:0)
我建议使用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