繁体   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