簡體   English   中英

為什么協程方法只能在Unity3D中工作一次

[英]Why Coroutine Method Work Only Once Unity3D

我有一個要滑動的對象,例如,向上滑動時,該對象應從A點平穩地向前移動到B點,向右滑動則該對象平穩地向右移動等。

為此,我嘗試了LerpMoveTowardsSmoothDamp,但是每次對象僅從點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

因此,您總是在當前位置和目標之間開始新的插值。 因此,距離越來越小,但實際上並沒有到達最終位置(盡管看起來確實如此)。

此外,您混合positionlocalPosition有那么如果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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM