[英]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.