Почему метод сопрограммы работает только один раз Unity3D - PullRequest
0 голосов
/ 22 марта 2019

У меня есть объект, который я хочу переместить с помощью пальца, например, когда проведите пальцем вверх, объект должен плавно двигаться вперед от точки A к точке B, проведите пальцем вправо, чтобы объект плавно переместился вправо и т. Д. *

Для этого я попытался Lerp , MoveTowards и SmoothDamp , но каждый раз, когда объект просто исчезал из точки A и появлялся в точке Bмгновенно.

Итак, я использовал сопрограмму, чтобы дать время движению, и, как вы можете видеть в коде ниже, есть 4 метода сопрограммы, каждый из которых предназначен для направления.у меня проблема в том, что при воспроизведении первое движение работает правильно, но при втором пролистывании объект не достиг точки назначения, а также третье движение и объект имеют некоторые странные движения.

МожетВы говорите мне, что не так в моем коде?

Вот методы Coroutine для движений:

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 ]

1 голос
/ 22 марта 2019

Ваш первый сопрограмм работает, потому что: Vector3 DestinationF = новый Vector3 (transform.position.x, transform.position.y, transform.position.z + DistanceF);

приведет к положительной позиции, поэтому расстояние будет больше 0:

while (Vector3.Distance(transform.localPosition, DestinationF) > 0)

С другой стороны, при вычитании расстояния B из значения z:

Vector3 DestinationB = new Vector3(transform.position.x, transform.position.y, transform.position.z - DistanceB);

может привести к отрицательному значению, поэтому:

while (Vector3.Distance(transform.localPosition, DestinationB) > 0)

начнется с <0, поэтому условие никогда не будет выполнено.Проверьте свое состояние.Вы хотите абсолютные значения или не равны 0? </p>

0 голосов
/ 22 марта 2019

Проблема в том, что вы никогда не достигнете цели.

Ваш рывок с коэффициентом

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 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...