为什么协程方法只能在Unity3D中工作一次

时间:2019-03-22 12:09:28

标签: c# 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());
        }

    }

2 个答案:

答案 0 :(得分:1)

您的第一个协程之所以能够工作,是因为:     Vector3 DestinationF =新的Vector3(transform.position.x,transform.position.y,transformationposition.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?

答案 1 :(得分: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 allways 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;
}