[英]Why Coroutine Method Work Only Once Unity3D
我有一个要滑动的对象,例如,向上滑动时,该对象应从A点平稳地向前移动到B点,向右滑动则该对象平稳地向右移动等。
为此,我尝试了Lerp , MoveTowards和SmoothDamp,但是每次对象仅从点A消失并立即出现在点B上。
因此,我使用协程为运动提供了时间,正如您在下面的代码波纹中所见,有4种协程方法,每个方法都针对一个方向。 我的问题是,在播放时,第一个动作正常,但是在第二次滑动中,对象没有到达目标点,第三个动作和对象也有一些奇怪的动作。
你能告诉我我的代码有什么问题吗?
这是协程的移动方法:
public IEnumerator MoveForward()
{
Vector3 DestinationF = new Vector3(transform.position.x, transform.position.y, transform.position.z + DistanceF);
while (Vector3.Distance(transform.localPosition, DestinationF) > 0)
{
float totalMovementTimeF = 0.3f;
float currentMovementTimeF = 0f;
currentMovementTimeF += Time.deltaTime;
transform.localPosition = Vector3.Lerp(transform.position, DestinationF, currentMovementTimeF / totalMovementTimeF);
yield return null;
}
}
public IEnumerator MoveBackward()
{
Vector3 DestinationB = new Vector3(transform.position.x, transform.position.y, transform.position.z - DistanceB);
while (Vector3.Distance(transform.localPosition, DestinationB) > 0)
{
float totalMovementTimeB = 0.3f;
float currentMovementTimeB = 0f;
currentMovementTimeB += Time.deltaTime;
transform.localPosition = Vector3.Lerp(transform.position, DestinationB, currentMovementTimeB / totalMovementTimeB);
yield return null;
}
}
并且仍然有2个协程方法MoveRight()和MoveLeft()。
这是滑动方向的代码:
if (Input.GetMouseButtonDown(0))
{
//save began touch 2d point
firstPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
}
if (Input.GetMouseButtonUp(0))
{
//save ended touch 2d point
secondPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
//create vector from the two points
currentSwipe = new Vector3(secondPressPos.x - firstPressPos.x, secondPressPos.y - firstPressPos.y);
//normalize the 2d vector
currentSwipe.Normalize();
// swipe up
if (currentSwipe.y > 0 && currentSwipe.x > -0.5f && currentSwipe.x < 0.5f)
{
StartCoroutine(MoveForward());
}
// swipe down
if (currentSwipe.y < 0 && currentSwipe.x > -0.5f && currentSwipe.x < 0.5f)
{
StartCoroutine(MoveBackward());
}
//swipe left
if (currentSwipe.x < 0 && currentSwipe.y > -0.5f && currentSwipe.y < 0.5f)
{
StartCoroutine(MoveLeft());
}
//swipe right
if (currentSwipe.x > 0 && currentSwipe.y > -0.5f && currentSwipe.y < 0.5f)
{
StartCoroutine(MoveRight());
}
}
您的第一个协程之所以起作用,是因为:Vector3 DestinationF = new Vector3(transform.position.x,transform.position.y,transform.position.z + DistanceF);
将产生一个正位置,因此,距离将大于0:
while (Vector3.Distance(transform.localPosition, DestinationF) > 0)
另一方面,从z值减去distanceB时:
Vector3 DestinationB = new Vector3(transform.position.x, transform.position.y, transform.position.z - DistanceB);
可能会导致负值,因此:
while (Vector3.Distance(transform.localPosition, DestinationB) > 0)
将从<0开始,因此永远不会满足该条件。 检查您的状况。 您要绝对值还是不等于0?
问题是您永远无法达到目标。
你忍受的因素
currentMovementTimeF / totalMovementTimeF
没有太大的意义,因为您将每一帧都重置为
var currentMovementTimeF = Time.deltaTime;
在大多数情况下,它会< 0.3f
(这意味着您每秒只有约3帧),因此始终为
currentMovementTimeF < totalMovementTimeF
因此
currentMovementTimeF / totalMovementTimeF < 1
因此,您总是在当前位置和目标之间开始新的插值。 因此,距离越来越小,但实际上并没有到达最终位置(尽管看起来确实如此)。
此外,您混合position
和localPosition
有那么如果GameObject
不在根级别的它变得更糟糕!
相反,您想要的是使用MoveTowards
以某个speed
探测。 (基于位置)
// adjust these in the Inspector
public float speed;
public float MoveDistance;
public IEnumerator Move(Vector3 direction)
{
var destinaton = transform.position + direction * MoveDistance;
while (Vector3.Distance(transform.position, destinaton) > 0)
{
transform.position = Vector3.MoveTowards(transform.position, MoveDistance, Time.deltaTime* speed);
yield return null;
}
}
MoveTowards
确保没有超调。
或使用Lerp(基于时间)
// adjust these in the Inspector
public float totalMovementTime = 0.3f;
public float MoveDistance;
public IEnumerator Move(Vector3 direction)
{
var originalPosition = transform.position;
var destination = transform.position + direction * MoveDistance;
// here you could make it even more accurate
// by moving always with the same speed
// regardless how far the object is from the target
//var moveDuration = totalMovementTime * Vector3.Distance(transform.position, destinaton);
// and than replacing totalMovementTime with moveDuration
var currentDuration = 0.0f;
while (currentDuration < totalMovementTime)
{
transform.position = Vector3.Lerp(originalPosition, destination, currentDuration / totalMovementTime);
currentDuration += Time.deltaTime;
yield return null;
}
// to be really sure set a fixed position in the end
transform.position = destinaton;
}
另一个问题是,您目前仍可以启动两个并发的协程,从而导致异常行为。 您宁可在每次启动新程序时都中断协程
if (currentSwipe.y > 0 && currentSwipe.x > -0.5f && currentSwipe.x < 0.5f)
{
// stop all current routines
stopAllCoroutines();
StartCoroutine(MoveForward());
}
或添加标志以仅运行一个例程,同时忽略输入:
private bool isSwiping;
public IEnumerator MoveForward()
{
if(isSwiping)
{
Debug.LogWarning("Already swiping -> ignored", this);
yield break;
}
isSwiping = true;
//...
isSwiping = false;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.